From 3725aedd02d9b24c1239610066dd62387ef4d5a9 Mon Sep 17 00:00:00 2001 From: dale_mellor Date: Fri, 4 Jul 2003 08:09:04 +0000 Subject: [PATCH 001/239] Initial version. Production quality, fully complete source but contains known bugs (lots!) --- AUTHORS | 1 + BUGS | 13 + ChangeLog | 30 ++ NEWS | 24 + README | 50 +++ TODO | 43 ++ config.scm.in | 27 ++ configure.ac | 82 ++++ crontab.scm | 199 +++++++++ email.scm | 182 ++++++++ environment.scm | 121 +++++ makefile.am | 61 +++ makefile.ed | 42 ++ mcron.c.template | 124 ++++++ mcron.scm | 846 +++++++++++++++++++++++++++++++++++ mcron.texinfo | 1094 ++++++++++++++++++++++++++++++++++++++++++++++ vixie.scm | 452 +++++++++++++++++++ 17 files changed, 3391 insertions(+) create mode 100644 AUTHORS create mode 100644 BUGS create mode 100644 ChangeLog create mode 100644 NEWS create mode 100644 README create mode 100644 TODO create mode 100644 config.scm.in create mode 100644 configure.ac create mode 100644 crontab.scm create mode 100644 email.scm create mode 100644 environment.scm create mode 100644 makefile.am create mode 100644 makefile.ed create mode 100644 mcron.c.template create mode 100644 mcron.scm create mode 100644 mcron.texinfo create mode 100644 vixie.scm diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..da27b1c --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Dale Mellor (dale_mellor@users.sourceforge.net) diff --git a/BUGS b/BUGS new file mode 100644 index 0000000..9eabf92 --- /dev/null +++ b/BUGS @@ -0,0 +1,13 @@ + -*-text-*- + +* If two users modify their crontabs simultaneously, there will be contention + for /var/cron/update between themselves and with the main daemon. + +* 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. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..ae6a219 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,30 @@ +2003-06-30 hydro23 > + + * mcron.scm: Introduced arbiters to marshall access to updates + structure between main routing and HUP signal action procedure. + + * crontab.scm: When an empty /tmp file is produced for editing, + make it owned by the real user (so he can edit it). + + * mcron.scm, makefile.am: Check explicitly for root user when + running cron personality. Install with only root execute + permission. + + * mcron.scm: Don't create /var/run/cron.pid if the -s option has + been used (this is an undocumented possibility). + + * configure.ac, config.scm.in: Added configure option + --enable-debug to determine whether debugging and traceback should + be turned on. + + * Version bumped to 0.99.2. + + +2003-06-28 Dale Mellor + + * First cut, fully functional, production quality code, just needs + testing... + + * Version set at 0.99.1 + + diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..5050482 --- /dev/null +++ b/NEWS @@ -0,0 +1,24 @@ +Historic moments in the life of mcron. + +Copyright (C) 1992, 1993, 1995-2002 Free Software Foundation, Inc. +See the end for copying conditions. + +Please send bug reports to dale_mellor@users.sourceforge.net. + + + + +---------------------------------------------------------------------- +Copyright information: + +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/README b/README new file mode 100644 index 0000000..06ccae1 --- /dev/null +++ b/README @@ -0,0 +1,50 @@ +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...). + + +---------------------------------------------------------------------- +IMPORTANT NOTICES + +Read the BUGS file. + +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. +---------------------------------------------------------------------- + + +See the file INSTALL for building and installation instructions. + +After installation, read the info file for full instructions for use (type +`info mcron' at the command line). + +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: + dale_mellor@users.sourceforge.net + +Mcron is free software. See the file COPYING for copying conditions. diff --git a/TODO b/TODO new file mode 100644 index 0000000..5f61fcf --- /dev/null +++ b/TODO @@ -0,0 +1,43 @@ +Maybe in the near future... + + * Logging. + + * Check POSIX compliance. + + + +There are no plans to actually do the following any time soon... + + * Develop at, batch modes of operation. + + * Make compatibilities with other crons (BSD, SYSV, Solaris, Dillon's, ...) + + * Port to BSD, other operating systems. + + * Full security audit for Vixie mode. + + * Move internal functions into a namespace such that configuration files + cannot interfere with mcron itself. + + + +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). + + * 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). + + + +May happen if version 2.0 ever materializes... + + * 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 + just CGI personality. + + * GTK+/Bononbo interface. diff --git a/config.scm.in b/config.scm.in new file mode 100644 index 0000000..f31ac1e --- /dev/null +++ b/config.scm.in @@ -0,0 +1,27 @@ +;; -*-scheme-*- + +;; Copyright (C) 2003 Dale Mellor +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +;; USA. + + +;; Some constants set by the configuration process. + +(define config-debug @CONFIG_DEBUG@) +(define config-package-string "@PACKAGE_STRING@") +(define config-package-bugreport "@PACKAGE_BUGREPORT@") +(define config-sendmail "@SENDMAIL@") +(define config-cat "@CAT@") diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..f56b111 --- /dev/null +++ b/configure.ac @@ -0,0 +1,82 @@ +# -*- Autoconf -*- +# 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) +AM_INIT_AUTOMAKE + + +AC_MSG_CHECKING([whether debugging is requested]) +AC_ARG_ENABLE(debug, + AC_HELP_STRING([--enable-debug], + [enable debugging and traceback on error]), + CONFIG_DEBUG=$enableval, + CONFIG_DEBUG=no) +AC_MSG_RESULT($CONFIG_DEBUG) +if test "$CONFIG_DEBUG" = "no"; then + CONFIG_DEBUG="#f" +else + CONFIG_DEBUG="#t" +fi +AC_SUBST(CONFIG_DEBUG) + + +AC_PROG_CC +GUILE_PROGS +GUILE_FLAGS + +# Checks for programs. + # AC_CHECK_PROG(CHMOD, chmod, chmod) +AC_CHECK_PROGS(CHMOD, chmod) +if test "x$ac_cv_prog_CHMOD" = "x"; then + AC_MSG_ERROR(chmod not found) +fi +AC_CHECK_PROGS(ED, ed) +if test "x$ac_cv_prog_ED" = "x"; then + AC_MSG_ERROR(ed not found) +fi +AC_CHECK_PROGS(CAT, cat) +if test "x$ac_cv_prog_CAT" = "x"; then + AC_MSG_ERROR(cat not found) +fi +AC_CHECK_PROGS(WHICH, which) +if test "x$ac_cv_prog_WHICH" = "x"; then + AC_MSG_ERROR(which not found) +fi + +# Now find a sendmail or equivalent. + +AC_CHECK_PROGS(SENDMAIL, sendmail) +if test "x$ac_cv_prog_SENDMAIL" != "x"; then + AC_MSG_CHECKING(sendmail path and arguments) + ac_cv_prog_SENDMAIL="`$ac_cv_prog_WHICH sendmail` -FCronDaemon -odi -oem " +dnl -or0s" + AC_MSG_RESULT($ac_cv_prog_SENDMAIL) + +else + AC_CHECK_PROGS(SENDMAIL, mail) + if test "x$ac_cv_prog_SENDMAIL" != "x"; then + AC_MSG_CHECKING(mail path) + ac_cv_prog_SENDMAIL="`$ac_cv_prog_WHICH sendmail` -d " + AC_MSG_RESULT($ac_cv_prog_SENDMAIL) + else + AC_MSG_RESULT(No mail program found) + fi +fi +SENDMAIL=$ac_cv_prog_SENDMAIL + + +# Checks for libraries. + +# Checks for header files. + +# Checks for typedefs, structures, and compiler characteristics. + +# Checks for library functions. + +real_program_prefix=`echo $program_prefix | sed s/NONE//` +AC_SUBST(real_program_prefix) + + +AC_CONFIG_FILES(makefile config.scm) +AC_OUTPUT diff --git a/crontab.scm b/crontab.scm new file mode 100644 index 0000000..417a900 --- /dev/null +++ b/crontab.scm @@ -0,0 +1,199 @@ +;; Copyright (C) 2003 Dale Mellor +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +;; USA. + + +;; Apart from the collecting of options and the handling of --help and --version +;; (which are done in the mcron.scm file), this file provides all the +;; functionality of the crontab personality. It is designed to be loaded and run +;; once, and then the calling program can exit and the crontab program will have +;; completed its function. + + + +;; Procedure to communicate with running cron daemon that a user has modified +;; his crontab. The user name is placed in /var/cron/update, and the process +;; whose PID is held in /var/run/cron.pid is sent a SIGHUP. + +(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))) + (lambda (key . args) + (display "Warning: a cron daemon is not running.\n")))) + + + +;; Procedure to scan a file containing one user name per line (such as +;; /var/cron/allow and /var/cron/deny), and determine if the given name is in +;; there. The procedure returns #t, #f, or '() if the file does not exist. + +(define (in-access-file? file name) + (catch #t (lambda () + (with-input-from-file file (lambda () + (let loop ((input (read-line))) + (if (eof-object? input) + #f + (if (string=? input name) + #t + (loop (read-line)))))))) + (lambda (key . args) '()))) + + + +;; This program should have been installed SUID root. Here we get the passwd +;; entry for the real user who is running this program. + +(define crontab-real-user (passwd:name (getpw (getuid)))) + + + +;; If the real user is not allowed to use crontab due to the /var/cron/allow +;; and/or /var/cron/deny files, bomb out now. + +(if (or (eq? (in-access-file? "/var/cron/allow" crontab-real-user) #f) + (eq? (in-access-file? "/var/cron/deny" crontab-real-user) #t)) + (begin + (display "Access denied by system operator.\n") + (primitive-exit 6))) + + + +;; Iff the real user is root, he can use the -u option to access files of +;; another user. + +(define crontab-user + (option-ref options 'user crontab-real-user)) + + + +;; So now we know which crontab file we will be manipulating. + +(define crontab-file (string-append "/var/cron/tabs/" crontab-user)) + + + +;; Check that no more than one of the mutually exclusive options are being used. + +(if (> (+ (if (option-ref options 'edit #f) 1 0) + (if (option-ref options 'list #f) 1 0) + (if (option-ref options 'remove #f) 1 0)) + 1) + (begin + (display "crontab: Only one of options -e, -l or -r can be used.\n") + (primitive-exit 7))) + + + +;; Check that a non-root user is trying to read someone else's files. + +(if (and (not (eqv? (getuid) 0)) + (option-ref options 'user #f)) + (begin (display "crontab: Only root can use the -u option.\n") + (primitive-exit 8))) + + + +;; There are four possible sub-personalities to the crontab personality: list, +;; remove, edit and replace (when the user uses no options but supplies file +;; names on the command line). + +(cond + + + ;; In the list personality, we simply open the crontab and copy it + ;; character-by-character to the standard output. If anything goes wrong, it + ;; can only mean that this user does not have a crontab file. + + ((option-ref options 'list #f) + (catch #t (lambda () + (with-input-from-file crontab-file (lambda () + (do ((input (read-char) (read-char))) + ((eof-object? input)) + (display input))))) + (lambda (key . args) + (display (string-append "No crontab for " + crontab-user + " exists.\n"))))) + + + ;; In the edit personality, we determine the name of a temporary file and an + ;; editor command, copy an existing crontab file (if it is there) to the + ;; temporary file, making sure the ownership is set so the real user can edit + ;; it; once the editor returns we try to read the file to check that it is + ;; parseable (but do nothing more with the configuration), and if it is okay + ;; (this program is still running!) we move the temporary file to the real + ;; 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 (if (getenv "VISUAL") (getenv "VISUAL") + (if (getenv "EDITOR") (getenv "EDITOR") + "vi")))) + (catch #t + (lambda () (copy-file crontab-file temp-file)) + (lambda (key . args) (with-output-to-file temp-file (lambda () #t)))) + (chown temp-file (getuid) (getgid)) + (system (string-append editor " " temp-file)) + (read-vixie-file temp-file) + (copy-file temp-file crontab-file) + (delete-file temp-file) + (hit-server crontab-user))) + + + ;; In the remove personality we simply make an effort to delete the crontab and + ;; wake the daemon. No worries if this fails. + + ((option-ref options 'remove #f) + (catch #t (lambda () (delete-file crontab-file) + (hit-server crontab-user)) + (lambda (key . args) #t))) + + + ;; In the case of the replace personality we loop over all the arguments on the + ;; command line, and for each one parse the file to make sure it is parseable + ;; (but subsequently ignore the configuration), and all being well we copy it + ;; to the crontab location; we deal with the standard input in the same way but + ;; different. :-) In either case the server is woken so that it will read the + ;; newly installed crontab. + + ((not (null? (option-ref options '() '()))) + (let ((input-file (car (option-ref options '() '())))) + (if (string=? input-file "-") + (let ((input-string (stdin->string))) + (read-vixie-port (open-input-string input-string)) + (with-output-to-file crontab-file (lambda () + (display input-string)))) + (begin + (read-vixie-file input-file) + (copy-file input-file crontab-file)))) + (hit-server crontab-user)) + + + ;; The user is being silly. The message here is identical to the one Vixie cron + ;; used to put out, for total compatibility. + + (else + (display + "crontab: usage error: file name must be specified for replace.\n") + (primitive-exit 15))) diff --git a/email.scm b/email.scm new file mode 100644 index 0000000..ec300a7 --- /dev/null +++ b/email.scm @@ -0,0 +1,182 @@ +;; Copyright (C) 2003 Dale Mellor +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +;; USA. + + +;; This file provides the (with-mail-out action . user) procedure. This +;; procedure runs the action in a child process, allowing the user control over +;; the input and output (including standard error). The input is governed (only +;; in the case of a string action) by the placing of percentage signs in the +;; string; the first delimits the true action from the standard input, and +;; subsequent ones denote newlines to be placed into the input. The output (if +;; there actually is any) is controlled by the MAILTO environment variable. If +;; this is not defined, output is e-mailed to the user passed as argument, if +;; any, or else the owner of the action; if defined but empty then any output is +;; sunk to /dev/null; otherwise output is e-mailed to the address held in the +;; MAILTO variable. + + +;; An action string consists of a sequence of characters forming a command +;; executable by the shell, possibly followed by an non-escaped percentage +;; sign. The text after the percentage sign is to be fed to the command's +;; standard input, with further unescaped percents being substituted with +;; newlines. The escape character can itself be escaped. +;; +;; This regexp separates the two halves of the string, and indeed determines if +;; the second part is present. + +(define action-string-regexp (make-regexp "((\\\\%|[^%])*)%(.*)$")) + + + +;; This regexp identifies an escaped percentage sign. + +(define e-percent (make-regexp "\\\\%")) + + +;; Function to execute some action (this may be a shell command, lamdba function +;; or list of scheme procedures) in a forked process, with the input coming from +;; the string, and output (including the error output) being sent to a pipe +;; opened on a mail transport. + +(use-modules (ice-9 popen)) + +(define (with-mail-out action . user) + + ;; Determine the name of the user who is to recieve the mail, looking for a + ;; name in the optional user argument, then in the MAILTO environment + ;; variable, and finally in the LOGNAME environment variable. (The case + ;; MAILTO="" is dealt with specially below.) + + (let* ((mailto (getenv "MAILTO")) + (user (cond (mailto mailto) + ((not (null? user)) (car user)) + (else (getenv "LOGNAME")))) + (parent->child (pipe)) + (child->parent (pipe)) + (child-pid (primitive-fork))) + + + ;; The child process. Close redundant ends of pipes, remap the standard + ;; streams, and run the action, taking care to chop off the input part of an + ;; action string. + + (if (eqv? child-pid 0) + (begin + (close (cdr parent->child)) + (close (car child->parent)) + + (dup2 (port->fdes (car parent->child)) 0) + (close (car parent->child)) + (dup2 (port->fdes (cdr child->parent)) 1) + (close (cdr child->parent)) + (dup2 1 2) + + (cond ((string? action) + (let ((match (regexp-exec action-string-regexp action))) + (system (if match + (let ((action (match:substring match 1))) + (do ((match (regexp-exec e-percent action) + (regexp-exec e-percent action))) + ((not match)) + (set! action (string-append + (match:prefix match) + "%" + (match:suffix match)))) + action) + action)))) + + ((procedure? action) (action)) + ((list? action) (primitive-eval action))) + + (primitive-exit 0))) + + + ;; The parent process. Get rid of redundant pipe ends. + + (close (car parent->child)) + (close (cdr child->parent)) + + + ;; Put stuff to child from after '%' in command line, replacing + ;; other %'s with newlines. Ugly or what? + + (if (string? action) + (let ((port (cdr parent->child)) + (match (regexp-exec action-string-regexp action))) + (if (and match + (match:substring match 3)) + (with-input-from-string (match:substring match 3) + (lambda () + (let loop () + (let ((next-char (read-char))) + (if (not (eof-object? next-char)) + (cond + ((char=? next-char #\%) + (newline port) + (loop)) + ((char=? next-char #\\) + (let ((escape (read-char))) + (if (eof-object? escape) + (display #\\ port) + (if (char=? escape #\%) + (begin + (display #\% port) + (loop)) + (begin + (display #\\ port) + (display escape port) + (loop)))))) + (else + (display next-char port) + (loop))))))))))) + + + ;; So the child process doesn't hang on to its input expecting more stuff. + + (close (cdr parent->child)) + + + ;; That's got streaming into the child's input out of the way, now we stream + ;; the child's output to a mail sink, but only if there is something there + ;; in the first place. + + (if (eof-object? (peek-char (car child->parent))) + + (read-char (car child->parent)) + + (begin + (set-current-output-port (if (and (string? mailto) + (string=? mailto "")) + (open-output-file "/dev/null") + (open-output-pipe + (string-append config-sendmail + " " + user)))) + (set-current-input-port (car child->parent)) + (display "To: ") (display user) (newline) + (display "From: mcron") (newline) + (display (string-append "Subject: " user "@" (gethostname))) + (newline) + (newline) + + (do ((next-char (read-char) (read-char))) + ((eof-object? next-char)) + (display next-char)))) + + (close (car child->parent)) + + (waitpid child-pid))) diff --git a/environment.scm b/environment.scm new file mode 100644 index 0000000..e4d59a8 --- /dev/null +++ b/environment.scm @@ -0,0 +1,121 @@ +;; Copyright (C) 2003 Dale Mellor +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +;; USA. + + + +;; This file defines the global variable current-environment-mods, and the +;; procedures append-environment-mods (which is available to user configuration +;; files), clear-environment-mods, modify-environment, and +;; parse-vixie-environment. The idea is that the current-environment-mods is a +;; list of pairs of environment names and values, and represents the cumulated +;; environment settings in a configuration file. When a job definition is seen +;; in a configuration file, the current-environment-mods are copied into the +;; internal job description, and when the job actually runs these environment +;; modifications are applied to the UNIX environment in which the job runs. + + + +;; The env-alist is an association list of variable names and values. Variables +;; later in the list will take precedence over variables before. We return a +;; fixed-up version in which some variables are given specific default values +;; (which the user can override), and one variable which the user is not allowed +;; to control is added at the end of the list. + +(define (impose-default-environment env-alist passwd-entry) + (append (list (cons "HOME" (passwd:dir passwd-entry)) + (cons "CWD" (passwd:dir passwd-entry)) + (cons "SHELL" (passwd:shell passwd-entry)) + '("TERM" . #f) + '("TERMCAP" . #f)) + env-alist + (list (cons "LOGNAME" (passwd:name passwd-entry)) + (cons "USER" (passwd:name passwd-entry))))) + + + + +;; Modify the UNIX environment for the current process according to the given +;; association list of variables, with the default variable values imposed. + +(define (modify-environment env-alist passwd-entry) + (for-each (lambda (variable) + (setenv (car variable) (cdr variable))) + (impose-default-environment env-alist passwd-entry))) + + + + +;; As we parse configuration files, we build up an alist of environment +;; variables here. + +(define current-environment-mods '()) + + + + +;; When we start to parse a new configuration file, we want to start with a +;; fresh environment (actually an umodified version of the pervading mcron +;; environment). + +(define (clear-environment-mods) + (set! current-environment-mods '())) + + + + +;; Procedure to add another environment setting to the alist above. This is used +;; both implicitly by the Vixie parser, and can be used directly by users in +;; scheme configuration files. The return value is purely for the convenience of +;; the parse-vixie-environment procedure below. + +(define (append-environment-mods name value) + (set! current-environment-mods (append current-environment-mods + (list (cons name value)))) + #t) + + + + +;; Procedure to act on an environment variable specification in a Vixie-style +;; configuration file, by adding an entry to the alist above. Returns #t if the +;; operation was successful, #f if the line could not be interpreted as an +;; environment specification. + +(define parse-vixie-environment-regexp1 + (make-regexp + "^[ \t]*([[:alpha:]_][[:alnum:]_]*)[ \t]*=[ \t]*\"(.*)\"[ \t]*$")) +(define parse-vixie-environment-regexp2 + (make-regexp + "^[ \t]*([[:alpha:]_][[:alnum:]_]*)[ \t]*=[ \t]*\'(.*)\'[ \t]*$")) +(define parse-vixie-environment-regexp3 + (make-regexp + "^[ \t]*([[:alpha:]_][[:alnum:]_]*)[ \t]*=[ \t]*(.*[^ \t])[ \t]*$")) +(define parse-vixie-environment-regexp4 + (make-regexp + "^[ \t]*([[:alpha:]_][[:alnum:]_]*)[ \t]*=[ \t]*$")) + +(use-modules (srfi srfi-2)) + +(define (parse-vixie-environment string) + (let ((match (or (regexp-exec parse-vixie-environment-regexp1 string) + (regexp-exec parse-vixie-environment-regexp2 string) + (regexp-exec parse-vixie-environment-regexp3 string)))) + (if match + (append-environment-mods (match:substring match 1) + (match:substring match 2)) + (and-let* ((match (regexp-exec parse-vixie-environment-regexp4 string))) + (append-environment-mods (match:substring match 1) #f))))) diff --git a/makefile.am b/makefile.am new file mode 100644 index 0000000..00b54ee --- /dev/null +++ b/makefile.am @@ -0,0 +1,61 @@ +## Makefile for the toplevel directory of mcron. +## Copyright (C) 2003 Dale Mellor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2, or (at your option) +## any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +## Process this file with automake to produce Makefile.in + +ED = @ED@ + +MAINTAINERCLEANFILES = configure makefile makefile.in \ + install-sh missing mkinstalldirs texinfo.tex INSTALL \ + aclocal.m4 compile depcomp COPYING + +CLEANFILES = mcron.c + +EXTRA_DIST = makefile.ed config.scm mcron.scm vixie.scm environment.scm \ + email.scm crontab.scm mcron.c.template + +info_TEXINFOS = mcron.texinfo +bin_PROGRAMS = mcron +mcron_SOURCES = mcron.c +mcron_LDFLAGS = @GUILE_LDFLAGS@ +mcron_CFLAGS = @GUILE_CFLAGS@ + +mcron.c : config.scm mcron.scm vixie.scm environment.scm email.scm crontab.scm \ + makefile.ed mcron.c.template + @echo 'Building mcron.c...' + @$(ED) < makefile.ed > /dev/null 2>&1 + @rm -f mcron.escaped.scm > /dev/null 2>&1 + +install-exec-local: + @if [ `id -u` -ne 0 ]; then \ + echo "*** MUST BE ROOT TO INSTALL MCRON ***"; \ + exit 1; \ + fi + +#full program prefix +fpp = $(DESTDIR)$(bindir)/@real_program_prefix@ + +install-exec-hook: + @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: + @rm -f $(fpp){cron,crontab}$(EXEEXT) diff --git a/makefile.ed b/makefile.ed new file mode 100644 index 0000000..15fe15d --- /dev/null +++ b/makefile.ed @@ -0,0 +1,42 @@ +# Copyright (C) 2003 Dale Mellor +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. +# +# +# +e mcron.scm +/\(load "config.scm"\)/d +-1r config.scm +/\(load "vixie.scm"\)/d +-1r vixie.scm +/\(load "email.scm"\)/d +-1r email.scm +/\(load "environment.scm"\)/d +-1r environment.scm +/\(load "crontab.scm"\)/d +-1r crontab.scm +%s/\\/\\\\/g +%s/"/\\"/g +%s/ *;;.*$/ /g +g/^ *$/d +%s/^/\"/ +%s/$/\"/ +w mcron.escaped.scm +e mcron.c.template +/GUILE_PROGRAM_GOES_HERE/d +-1r mcron.escaped.scm +w mcron.c +q diff --git a/mcron.c.template b/mcron.c.template new file mode 100644 index 0000000..8277732 --- /dev/null +++ b/mcron.c.template @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2003 Dale Mellor + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + + +/* + This C code represents the thinnest possible wrapper around the Guile code + which constitutes all the functionality of the mcron program. There are two + plus one reasons why we need to do this, and one very unfortunate + consequence. + + Firstly, SUID does not work on an executable script. In the end, it is + the execution of the translator, in our case guile, which determines the + effective user, and it is not wise to make the system guile installation + SUID root! + + Secondly, executable scripts show up in ugly ways in listings of the + system process table. Guile in particular, with its multi-line + #! ...\ \n -s ...!# + idiosyncracies shows up in process listings in a way that is difficult + to determine what program is actually running. + + A third reason for the C wrapper which might be mentioned is that a + security-conscious system administrator can choose to only install a + binary, thus removing the possibility of a user studying a guile script + and working out ways of hacking it to his own ends, or worse still + finding a way to modify it to his own ends. + + Unfortunately, running the guile script from inside a C program means + that the sigaction function does not work. Instead, it is necessary to + perform the signal processing in C. + + The guile code itself is substituted for the GU1LE_PROGRAM_GOES_HERE (sic) + token by the makefile, which processes the scheme to make it look like one + big string. +*/ + + + +#include +#include + + + +/* This is a function designed to be installed as a signal handler, for signals + which are supposed to initiate shutdown of this program. It calls the scheme + procedure (see mcron.scm for details) to do all the work, and then exits. */ + +void react_to_terminal_signal (int sig) +{ + scm_eval_string (scm_take0str ("(delete-run-file)") ); + exit (1); +} + + + +/* 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. */ + +SCM set_cron_signals () +{ + static struct sigaction sa; + memset (&sa, 0, sizeof (sa)); + sa.sa_handler = react_to_terminal_signal; + 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); + + return SCM_BOOL_T; +} + + + +/* The effective main function (i.e. the one that actually does some work). We + register the function above with the guile system, and then execute the mcron + guile program. */ + +void inner_main () +{ + scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); + + scm_eval_string (scm_take0str ( + GUILE_PROGRAM_GOES_HERE + ) ); +} + + + +/* The real main function. Does nothing but start up the guile subsystem. */ + +int main (int argc, char **argv) +{ + scm_boot_guile (argc, argv, inner_main, 0); + return 0; +} diff --git a/mcron.scm b/mcron.scm new file mode 100644 index 0000000..b41a88b --- /dev/null +++ b/mcron.scm @@ -0,0 +1,846 @@ +;; Copyright (C) 2003 Dale Mellor +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +;; USA. + + + +;; This is the 'main' routine for the whole system; the top of this file is the +;; global entry point (after the minimal C wrapper, mcron.c.template). To all +;; intents and purposes the program is pure Guile and starts here. +;; +;; This file is built into mcron.c.template by the makefile, which stringifies +;; the whole lot, and escapes quotation marks and escape characters +;; accordingly. Bear this in mind when considering literal multi-line strings. +;; +;; (load ...)'s are inlined by the makefile. + + +;; Make a note of the time the script started; regardless of how long it takes +;; to initialize things, we will run any job scheduled to run after this exact +;; second. + +(define configuration-time (current-time)) + + + +;; Pull in some constants set by the builder (via autoconf) at configuration +;; time. Turn debugging on if indicated. + +(load "config.scm") +(if config-debug (begin (debug-enable 'debug) + (debug-enable 'backtrace))) + + + +;; To determine the name of the program, scan the first item of the command line +;; backwards for the first non-alphabetic character. This allows names like +;; in.cron to be accepted as an invocation of the cron command. + +(use-modules (ice-9 regex)) + +(define command-name (match:substring (regexp-exec (make-regexp "[[:alpha:]]*$") + (car (command-line))))) + + + +;; We will be doing a lot of testing of the command name, so it makes sense to +;; perform the string comparisons once and for all here. + +(define command-type (cond ((string=? command-name "mcron") 'mcron) + ((or (string=? command-name "cron") + (string=? command-name "crond")) 'cron) + ((string=? command-name "crontab") 'crontab) + (else + (display "The command name is invalid.\n") + (primitive-exit 12)))) + + + +;; There are a different set of options for the crontab personality compared to +;; all the others, with the --help and --version options common to all the +;; personalities. + +(use-modules (ice-9 getopt-long)) + +(define options + (getopt-long (command-line) + (append + (case command-type ('crontab + '((user (single-char #\u) (value #t)) + (edit (single-char #\e) (value #f)) + (list (single-char #\l) (value #f)) + (remove (single-char #\r) (value #f)))) + (else `((schedule (single-char #\s) (value optional)) + (daemon (single-char #\d) (value #f)) + (stdin (single-char #\i) (value #t) + (predicate + ,(lambda (value) + (or (string=? "vixie" value) + (string=? "guile" value)))))))) + '((version (single-char #\v) (value #f)) + (help (single-char #\h) (value #f)))))) + + + + +;; If the user asked for the version of this program, give it to him and get +;; out. + +(if (option-ref options 'version #f) + (begin + (display (string-append "\n +" command-name " (" config-package-string ")\n +Written by Dale Mellor\n +\n +Copyright (C) 2003 Dale Mellor\n +This is free software; see the source for copying conditions. There is NO\n +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n +")) + (quit))) + + + +;; Likewise if the user requested the help text. + +(if (option-ref options 'help #f) + (begin + (display (string-append " +Usage: " (car (command-line)) +(case command-type ('mcron +" [OPTIONS] [FILES]\n +Run an mcron process according to the specifications in the FILES (`-' for\n +standard input), or use all the files in ~/.cron with .guile or .vixie\n +extensions.\n +\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 mcron\n + -d, --daemon Immediately detach the program from the terminal and\n + run as a daemon process\n + -i, --stdin=(guile|vixie) Format of data passed as standard input\n + (default guile)") + + ('cron +" [OPTIONS]\n +Unless an option is specified, run a cron daemon as a detached process, \n +reading all the information in the users' crontabs and in /etc/crontab.\n +\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") + + ('crontab + (string-append " [-u user] file\n" + " " (car (command-line)) " [-u user] { -e | -l | -r }\n" + " (default operation is replace, per 1003.2)\n" + " -e (edit user's crontab)\n" + " -l (list user's crontab)\n" + " -r (delete user's crontab)\n"))) + +"\n\n +Report bugs to " config-package-bugreport ".\n +")) + (quit))) + + +;;---------------------------------------------------------------------- +;; Perform setup processing specific to cron, crond personalities. +;;---------------------------------------------------------------------- + +;; This is called from the C front-end whenever a terminal signal is +;; received. We simply remove the /var/run/cron.pid file so that crontab and +;; other invokations of cron don't get the wrong idea that a daemon is currently +;; running. + +(define (delete-run-file) + (catch #t (lambda () (delete-file "/var/run/cron.pid")) + (lambda (key . args) #t)) + (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. +;; +;; Otherwise, clear the MAILTO environment variable so that output from cron +;; jobs is sent to the various users (this may still be overridden in the +;; configuration files), and call the function in the C wrapper to set up +;; terminal and hangup signal responses to vector to the two procedures +;; above. The PID file will be filled in properly later when we have forked our +;; daemon process (but not done if we are only viewing the schedules). + +(if (eq? command-type 'cron) + (begin + (if (not (eqv? (getuid) 0)) + (begin + (display "This program must be run by the root user (and should ") + (display "have been installed as such).\n") + (primitive-exit 16))) + (if (access? "/var/run/cron.pid" F_OK) + (begin + (display "A cron daemon is already running.\n") + (display " (If you are sure this is not true, remove the file\n") + (display " /var/run/cron.pid.)\n") + (primitive-exit 1))) + (if (not (option-ref options 'schedule #f)) + (with-output-to-file "/var/run/cron.pid" + (lambda () #t))) + (setenv "MAILTO" #f) + (c-set-cron-signals))) + + + +;;---------------------------------------------------------------------- +;; Define the functions available to the configuration files. +;;---------------------------------------------------------------------- + + +;; Define the with-mail-out command for configuration files to use (directly or +;; indirectly as is the case when we parse vixie-style files). + +(load "email.scm") + + + +;; Function (available to user configuration files) which produces a list of +;; values from start up to (but not including) end. An optional step may be +;; supplied, and (if positive) only every step'th value will go into the +;; list. For example, (range 1 6 2) returns '(1 3 5). + +(define (range start end . step) + (let ((step (if (or (null? step) + (<= (car step) 0)) + 1 + (car step)))) + (let loop ((start start)) + (if (>= start end) '() + (cons start + (loop (+ start step))))))) + + + +;; Internal function (not supposed to be used directly in configuration files) +;; which takes a value and a list of possible next values (all assumed less than +;; 9999). It returns a pair consisting of the smallest element of the list, and +;; the smallest element larger than the current value. If an example of the +;; latter cannot be found, 9999 will be returned. + +(define (find-best-next current next-list) + (let ((current-best (cons 9999 9999))) + (for-each (lambda (allowed-time) + (if (< allowed-time (car current-best)) + (set-car! current-best allowed-time)) + (if (and (> allowed-time current) + (< allowed-time (cdr current-best))) + (set-cdr! current-best allowed-time))) + next-list) + current-best)) + + + +;; Internal function to return the time corresponding to some near future +;; hour. If hour-list is not supplied, the time returned corresponds to the +;; start of the next hour of the day. +;; +;; If the hour-list is supplied the time returned corresponds to the first hour +;; of the day in the future which is contained in the list. If all the values in +;; the list are less than the current hour, then the time returned will +;; correspond to the first hour in the list *on the following day*. +;; +;; ... except that the function is actually generalized to deal with seconds, +;; minutes, etc., in an obvious way :-) +;; +;; Note that value-list always comes from an optional argument to a procedure, +;; so is wrapped up as the first element of a list (i.e. it is a list inside a +;; list). + +(define (bump-time time value-list component higher-component + set-component! set-higher-component!) + (if (null? value-list) + (set-component! time (+ (component time) 1)) + (let ((best-next (find-best-next (component time) (car value-list)))) + (if (eqv? 9999 (cdr best-next)) + (begin + (set-higher-component! time (+ (higher-component time) 1)) + (set-component! time (car best-next))) + (set-component! time (cdr best-next))))) + (car (mktime time))) + + + + +;; Set of configuration methods which use the above general function to bump +;; specific components of time to the next legitimate value. In each case, all +;; the components smaller than that of interest are taken to zero, so that for +;; example the time of the next year will be the time at which the next year +;; actually starts. + +(define (next-year-from current-time . year-list) + (let ((time (localtime current-time))) + (set-tm:mon time 0) + (set-tm:mday time 1) + (set-tm:hour time 0) + (set-tm:min time 0) + (set-tm:sec time 0) + (bump-time time year-list tm:year tm:year set-tm:year set-tm:year))) + +(define (next-month-from current-time . month-list) + (let ((time (localtime current-time))) + (set-tm:mday time 1) + (set-tm:hour time 0) + (set-tm:min time 0) + (set-tm:sec time 0) + (bump-time time month-list tm:mon tm:year set-tm:mon set-tm:year))) + +(define (next-day-from current-time . day-list) + (let ((time (localtime current-time))) + (set-tm:hour time 0) + (set-tm:min time 0) + (set-tm:sec time 0) + (bump-time time day-list tm:mday tm:mon set-tm:mday set-tm:mon))) + +(define (next-hour-from current-time . hour-list) + (let ((time (localtime current-time))) + (set-tm:min time 0) + (set-tm:sec time 0) + (bump-time time hour-list tm:hour tm:mday set-tm:hour set-tm:mday))) + +(define (next-minute-from current-time . minute-list) + (let ((time (localtime current-time))) + (set-tm:sec time 0) + (bump-time time minute-list tm:min tm:hour set-tm:min set-tm:hour))) + +(define (next-second-from current-time . second-list) + (let ((time (localtime current-time))) + (bump-time time second-list tm:sec tm:min set-tm:sec set-tm:min))) + + + +;; The current-action-time is the time a job was last run, the time from which +;; the next time to run a job must be computed. (When the program is first run, +;; this time is set to the configuration time so that jobs run from that moment +;; forwards.) Once we have this, we supply versions of the time computation +;; commands above which implicitly assume this value. + +(define current-action-time configuration-time) + + + +;; We want to provide functions which take a single optional argument (as well +;; as implicitly the current action time), but unlike usual scheme behaviour if +;; the argument is missing we want to act like it is really missing, and if it +;; is there we want to act like it is a genuine argument, not a list of +;; optionals. + +(define (maybe-args function args) + (if (null? args) + (function current-action-time) + (function current-action-time (car args)))) + + + +;; These are the convenience functions we were striving to define for the +;; configuration files. They are wrappers for the next-X-from functions above, +;; but implicitly use the current-action-time for the time argument. + +(define (next-year . args) (maybe-args next-year-from args)) +(define (next-month . args) (maybe-args next-month-from args)) +(define (next-day . args) (maybe-args next-day-from args)) +(define (next-hour . args) (maybe-args next-hour-from args)) +(define (next-minute . args) (maybe-args next-minute-from args)) +(define (next-second . args) (maybe-args next-second-from args)) + + + +;; The list of all jobs known to the system. Each element of the list is +;; +;; (vector user next-time-function action environment 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 +;; modifications that need making to the UNIX environment before the action is +;; run. The next-time elements is the only one that is modified during the +;; running of a cron process (i.e. all the others are set once and for all at +;; configuration time). + +(define job-list '()) + + + +;; Convenience functions for getting and setting the elements of a job object. + +(define (job:user job) (vector-ref job 0)) +(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)) + + + +;; Introduce the definition of an environment object, and provide methods for +;; its manipulation and application to the environment in which we run a job. + +(load "environment.scm") + + + +;; Introduce functions which can be used directly in configuration files or +;; indirectly to parse vixie-style time specification strings and manufacture +;; corresponding next-time functions like the ones above. + +(load "vixie.scm") + + + +;; The default user for running jobs is the current one (who invoked this +;; program). There are exceptions: when cron parses /etc/crontab the user is +;; specified on each individual line; when cron parses /var/cron/tabs/* the user +;; is derived from the filename of the crontab. These cases are dealt with by +;; mutating this variable. Note that the variable is only used at configuration +;; time; a UID is stored with each job and it is that which takes effect when +;; the job actually runs. + +(define configuration-user (getpw (getuid))) + + + +;; The job function, available to configuration files for adding a job rule to +;; the system. +;; +;; Here we must 'normalize' the next-time-function so that it is always a lambda +;; function which takes one argument (the last time the job ran) and returns a +;; single value (the next time the job should run). If the input value is a +;; string this is parsed as a Vixie-style time specification, and if it is a +;; list then we arrange to eval it (but note that such lists are expected to +;; ignore the function parameter - the last run time is always read from the +;; current-action-time global variable). A similar normalization is applied to +;; the action. +;; +;; Here we also compute the first time that the job is supposed to run, by +;; finding the next legitimate time from the current configuration time (set +;; right at the top of this program). +;; +;; Note that the new job is added at the front of the job-list (this is +;; 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) + (let ((action (cond ((procedure? action) action) + ((list? action) (lambda () (primitive-eval action))) + ((string? action) (lambda () (system action))) + (else + (display "job: invalid second argument (action; should be lamdba") + (display "function, string or list)\n") + (primitive-exit 2)))) + + (time-proc + (cond ((procedure? time-proc) time-proc) + ((string? time-proc) (parse-vixie-time time-proc)) + ((list? time-proc) (lambda (dummy) + (primitive-eval time-proc))) + (else + + (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)))) + + +;;---------------------------------------------------------------------- +;; End of definition of procedures for configuration files. +;;---------------------------------------------------------------------- + + + +;; Procedure to slurp the standard input into a string. + +(define (stdin->string) + (with-output-to-string (lambda () (do ((in (read-char) (read-char))) + ((eof-object? in)) + (display in))))) + + + +;; Now we have the procedures in place for dealing with the contents of +;; configuration files, the crontab personality is able to validate such +;; files. If the user requested the crontab personality, we load and run the +;; code here and then get out. + +(if (eq? command-type 'crontab) + (begin + (load "crontab.scm") + (quit))) + + + +;;---------------------------------------------------------------------- +;; Procedures for effecting the configuration process itself. +;;---------------------------------------------------------------------- + + +;; Procedure which processes any configuration file according to the +;; extension. If a file is not recognized, it is silently ignored (this deals +;; properly with most editors' backup files, for instance). + +(define guile-file-regexp (make-regexp "\\.gui(le)?$")) +(define vixie-file-regexp (make-regexp "\\.vix(ie)?$")) + +(define (process-user-file file-path) + (cond ((string=? file-path "-") + (if (string=? (option-ref options 'stdin "guile") "vixie") + (read-vixie-port (current-input-port)) + (eval-string (stdin->string)))) + ((regexp-exec guile-file-regexp file-path) + (load file-path)) + ((regexp-exec vixie-file-regexp file-path) + (read-vixie-file file-path)))) + + + +;; Procedure to run through all the files in a user's ~/.cron directory (only +;; happens under the mcron personality). + +(define (process-files-in-user-directory) + (catch #t (lambda () + (let* ((dir-path (string-append (passwd:dir configuration-user) + "/.cron")) + (directory (opendir dir-path))) + (do ((file-name (readdir directory) (readdir directory))) + ((eof-object? file-name) (closedir directory)) + (process-user-file (string-append dir-path + "/" + file-name))))) + (lambda (key . args) + (display "Cannot read files in your ~/.cron directory.\n") + (primitive-exit 13)))) + + + +;; Procedure to check that a user name is the 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. + +(define (valid-user user-name) + (setpwent) + (do ((entry (getpw) (getpw))) + ((or (not entry) + (string=? (passwd:name entry) user-name)) + (endpwent) + entry))) + + + +;; Procedure to process all the files in the crontab directory, making sure that +;; each file is for a legitimate user and setting the configuration-user to that +;; user. In this way, when the job procedure is run on behalf of the +;; configuration files, the jobs are registered with the system with the +;; appropriate user. Note that only the root user should be able to perform this +;; operation, but we leave it to the permissions on the /var/cron/tabs directory +;; to enforce this. + +(use-modules (srfi srfi-2)) + +(define (process-files-in-system-directory) +;;; (catch #t (lambda () + (let ((directory (opendir "/var/cron/tabs"))) + (do ((file-name (readdir directory) (readdir directory))) + ((eof-object? file-name) (closedir directory)) + (and-let* ((user (valid-user file-name))) + (set! configuration-user user) + (read-vixie-file (string-append "/var/cron/tabs/" + file-name))))) +;;; ) +;;; (lambda (key . args) +;;; (display "You do not have permission to access the system crontabs.\n") +;;; (primitive-exit 4))) + ) + + + +;; 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 +;; passed on the command line, or else all the ones in the user's .cron +;; directory. If we are running under the cron personality, we read the +;; /var/cron/tabs directory and also the /etc/crontab file. + +(case command-type + ('mcron (if (null? (option-ref options '() '())) + (process-files-in-user-directory) + (for-each (lambda (file-path) + (process-user-file file-path)) + (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))))) + + + +;;---------------------------------------------------------------------- +;; End of configuration section. +;; +;; Now the main execution loop. +;;---------------------------------------------------------------------- + + + +;; Procedure to locate the jobs in the global job-list with the lowest +;; (soonest) next-times. These are the jobs for which we must schedule the mcron +;; program (under any personality) to next wake up. The return value is a cons +;; cell consisting of the next time (maintained in the next-time variable) and a +;; list of the job entries that are to run at this time (maintained in the +;; next-jobs-list variable). +;; +;; The procedure works by first obtaining the time of the first job on the list, +;; and setting this job in the next-jobs-list. Then for each other entry on the +;; job-list, either the job runs earlier than any other that have been scanned, +;; in which case the next-time and next-jobs-list are re-initialized to +;; accomodate, or the job runs at the same time as the next job, in which case +;; the next-jobs-list is simply augmented with the new job, or else the job runs +;; later than others noted in which case we ignore it for now and continue to +;; 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)))) + + + +;; If the user has requested a schedule of jobs that will run, we provide the +;; information here and then get out. +;; +;; Start by determining the number of time points in the future that output is +;; required for. This may be provided on the command line as a parameter to the +;; --schedule option, or else we assume a default of 8. Having determined this +;; count we enter a loop of displaying the next set of jobs to run, artificially +;; forwarding the time to the next time point (instead of waiting for it to +;; occur as we would do in a normal run of mcron), and recurse around the loop +;; count times. + +(and-let* ((count (option-ref options 'schedule #f))) + (set! count (if (eq? count #t) + 8 + (string->number count))) + (if (<= count 0) (set! count 1)) + (do ((count count (- count 1))) + ((eqv? count 0)) + (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)) + (cdr next-jobs)))) + (quit)) + + + +;; For proper housekeeping, it is necessary to keep a record of the number of +;; child processes we fork off to run the jobs. + +(define number-children 0) + + + +;; For every job on the list, fork a process to run it (noting the fact by +;; increasing the number-children counter), and in the new process set up the +;; run-time environment exactly as it should be before running the job proper. +;; +;; In the parent, update the job entry by computing the next time the job needs +;; to run. + +(define (run-jobs jobs-list) + (for-each (lambda (job) + (if (eqv? (primitive-fork) 0) + (begin + (setuid (passwd:uid (job:user job))) + (chdir (passwd:dir (job:user job))) + (modify-environment (job:environment job) (job:user job)) + ((job:action job)) + (primitive-exit 0)) + (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))))) + jobs-list)) + + + +;; If we are supposed to run as a daemon process (either a --daemon option has +;; been explicitly used, or we are running as cron or crond), detach from the +;; terminal now. If we are running as cron, we can now write the PID file. + +(if (option-ref options 'daemon (eq? command-type 'cron)) + (begin + (if (not (eqv? (primitive-fork) 0)) + (quit)) + (setsid) + (if (eq? command-type 'cron) + (with-output-to-file "/var/run/cron.pid" + (lambda () (display (getpid)) (newline)))))) + + + +;; 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. + +(use-modules (srfi srfi-1)) + +(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. + + (let* ((next-jobs (find-next-jobs)) + (next-time (car next-jobs)) + (next-jobs-list (cdr next-jobs)) + (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)))) + (run-jobs next-jobs-list))) + + (do () ((or (<= number-children 0) + (eqv? (car (waitpid WAIT_ANY WNOHANG)) 0))) + (set! number-children (- number-children 1))) + + (main-loop)) diff --git a/mcron.texinfo b/mcron.texinfo new file mode 100644 index 0000000..4ceb290 --- /dev/null +++ b/mcron.texinfo @@ -0,0 +1,1094 @@ +\input texinfo +@c %**start of header +@setfilename mcron.info +@settitle mcron 1.0.0 +@c %**end of header + +@syncodeindex fn cp + +@copying +This file documents the @code{mcron} command for running jobs at +scheduled times. + +Copyright (C) 2003 Dale Mellor +This is free software. See the source files for the terms of the +copyright. + +@ignore +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. +@end ignore +@end copying + + +@ifinfo + +@dircategory Individual utilities + +@direntry +* mcron: (mcron). Run jobs at scheduled times. +@end direntry + +@end ifinfo + + +@titlepage +@title mcron - Mellor's cron daemon +@author Dale Mellor + +@page +@vskip 0pt plus 1fill +@insertcopying + +@end titlepage + +@contents + +@ifnottex +@node Top, Introduction, (dir), (dir) +@top mcron + +@insertcopying +@end ifnottex + +@menu +* Introduction:: Introducing mcron. +* Simple examples:: How to use mcron 99.9% of the time. +* Syntax:: All the possibilities for configuring cron jobs. +* Invoking:: What happens when you run the mcron command. +* Index:: The complete index. + +@detailmenu + --- The Detailed Node Listing --- + +Simple examples + +* Guile Simple Examples:: +* Vixie Simple Examples:: + +Full available syntax + +* Guile Syntax:: +* Extended Guile examples:: +* Vixie Syntax:: + +Extended Guile examples + +* AT commands:: +* Every second Sunday:: +* Two hours every day:: +* Missing the first appointment:: +* Penultimate day of every month:: + +Vixie + +* Paul Dixie's copyright:: +* Crontab file:: +* Incompatibilities with old Unices:: + +Detailed invoking + +* Running mcron:: +* Running cron or crond:: +* Running crontab:: +* Exit codes:: + +@end detailmenu +@end menu + +@node Introduction, Simple examples, Top, Top +@chapter Introducing mcron +@cindex introduction +@cindex mcron +The mcron program represents a complete re-think of the cron concept +originally found in the Berkeley and AT&T unices, and subsequently +rationalized by Paul Vixie. The original idea was to have a daemon +that wakes up every minute, scans a set of files under a special +directory, and determines from those files if any shell commands +should be executed in this minute. + +The new idea is to read the required command instructions, work out +which command needs to be executed next, and then sleep until the +inferred time has arrived. On waking the commands are run, and the +time of the next command is computed. Furthermore, the specifications +are written in scheme, allowing at the same time simple command +execution instructions and very much more flexible ones to be composed +than the original Vixie format. This has several useful advantages +over the original idea. + +@cindex advantages of mcron +@itemize @bullet +@item +Does not consume CPU resources when not needed. Many cron daemons only +run jobs once an hour, or even just once a day. +@item +Can easily allow for finer time-points to be specified, +i.e. seconds. In principle this could be extended to microseconds, but +this is not implemented. +@item +Times can be more or less regular. For example, a job that runs +every 17 hours can be specified, or a job that runs on the first +Sunday of every month. +@item +Times can be dynamic. Arbitrary Guile (scheme) code can be provided to +compute the next time that a command needs to be run. This could, for +example, take the system load into consideration. +@item +Turns out to be easy to provide complete backwards compatibility with +Vixie cron. +@item +Each user looks after his own files in his own directory. He can use +more than one to break up complicated cron specifications. +@item +Each user can run his own daemon. This removes the need for suid +programs to manipulate the crontabs, and eliminates many security +concerns that surround all existing cron programs. +@item +The user can obtain an advance schedule of all the jobs that are due +to run. +@item +Vixie cron is implemented in 4500 lines of C code; mcron is 1500 lines +of scheme, despite the fact that it offers many more features and much +more flexibility, and complete compatibility with Vixie cron. +@end itemize + +A full discussion of the design and philosophy of mcron can be found +in the white paper at http://.../mcron.html [FIXME]. + + +@node Simple examples, Syntax, Introduction, Top +@chapter Simple examples +The vast majority of uses of cron are sublimely simple: run a program +every hour, or every day. With this in mind the design of mcron has +been to allow such simple specifications to be made easily. The +examples show how to create the command descriptions, and subsequently +how to run mcron to make them happen. +@menu +* Guile Simple Examples:: +* Vixie Simple Examples:: +@end menu + +@node Guile Simple Examples, Vixie Simple Examples, Simple examples, Simple examples +@section Guile +@cindex guile examples +@cindex examples, guile +@cindex example, run a program every hour +You have an executable @code{my-program} in your home directory, which +you want to run every hour. Create a file @code{job.guile} in directory +@code{~/.cron} with the following contents + +@example +(job '(next-hour) "my-program") +@end example + +then run the command @code{mcron}. + +Want the program to run fifteen minutes past the hour, every two +hours? Edit the file to read + +@example +(job + '(next-minute-from + (next-hour (range 0 24 2)) + 15) + "my-program") +@end example + +and run the command @code{mcron}. + +Or, if you are not comfortable with Scheme, you could use (and see +also the next section) + +@example +(job "15 */2 * * *" "my-program") +@end example + +and run the @code{mcron} command. + +If you want to run other jobs, you can either add more lines to this +file, or you can create other files in your @code{.cron} directory +with the @code{.guile} extension. Alternatively, you can use any file +you want and pass it as an argument to @code{mcron}, or even pipe the +commands into the standard input. + + +@node Vixie Simple Examples, , Guile Simple Examples, Simple examples +@section Vixie +@cindex examples +@cindex examples, vixie +@cindex vixie examples +You have an executable @code{my-program} in your home directory, which +you want to run every hour. Create a file @code{job.vixie} in directory +@code{~/.cron} with the following contents + +@example +0 * * * * my-program +@end example + +then run the command @code{mcron}. + +@cindex vixie compatibility +@cindex compatibility +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 +on your system, by root. + +@node Syntax, Invoking, Simple examples, Top +@chapter Full available syntax +@menu +* Guile Syntax:: +* Extended Guile examples:: +* Vixie Syntax:: +@end menu +@node Guile Syntax, Extended Guile examples, Syntax, Syntax +@section Guile Syntax +@subsection Job specification +@cindex guile syntax +@cindex syntax, guile +@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. + +@cindex time specification, procedure +@cindex procedure time specification +The first argument can be a procedure, a list, or a string. If a +function is supplied, it must take exactly one argument, which will be +the ``current'' time in UNIX format, and the return value of the +function must be the time in UNIX format when this action should next +be run. The following functions are available to facilitate the +computation: + +@findex next-second-from +@code{(next-second-from time . args)} without arguments this +returns the second after the current one. With the extra arguments, +these form a list of seconds in the minute when the action should run, +and the function will return the time of the next allowed second +(which may be in the next minute of the hour). @footnote{Note that +while commands can be scheduled to run at any second, it is unlikely +that they will be executed then but some time shortly thereafter, +depending on the load on the system and the number of jobs that mcron +has to start at the same time.} + +@findex next-minute-from +@findex next-hour-from +@findex next-day-from +@findex next-week-from +@findex next-month-from +@findex next-year-from +Similarly to @code{next-second-from}, there are also +@code{next-minute-from}, @code{next-hour-from}, @code{next-day-from}, +@code{next-week-from}, @code{next-month-from}, @code{next-year-from}. + +@findex range +Furthermore, the optional argument can be fulfilled by the function +@code{(range start end . step)}, which will provide a list of values +from start to (but not including) end, with the step if given. For +example @code{(range 0 10 2)} will yield the list @code{'(0 2 4 6 8)}. + +@findex next-second +@findex next-minute +@findex next-hour +@findex next-day +@findex next-week +@findex next-month +@findex next-year +@cindex time specification, list +@cindex list time specification +If the first argument to the @code{job} function is a list, it is +taken to be program code made up of the functions @code{(next-second +. args)}, @code{(next-minute...)}, etc, where the optional arguments +can be supplied with the @code{(range)} function above (these +functions are analogous to the ones above except that they implicitly +assume the current time; it is supplied by the mcron core when the +list is eval'd). + +@cindex time specification +@cindex time specification, string +@cindex string time specification +@cindex time specification, vixie-style +@cindex vixie-style time specification +If the first argument to the @code{job} function is a string, it is +expected to be a Vixie cron-style time specification. See the section +on Vixie syntax for this. + +@cindex job execution +@cindex command execution +@cindex execution +The second argument to the @code{(job)} function can be either a +string, a list, or a function. In all cases the command is executed in +the user's home directory, under the user's own UID. If a string is +passed, it is assumed to be shell script and is executed with the +user's default shell. If a list is passed it is assumed to be scheme +code and is eval'd as such. A supplied function should take exactly +zero arguments, and will be called at the pertinent times. + +@subsection Sending output as e-mail +@cindex email output +@cindex email from guile script +@cindex standard input to commands +@findex with-mail-out +When jobs are specified in a vixie-style configuration, the command is +broken at a percentage sign, and the stuff that comes after this is +sent into the command's standard input. Furthermore, any output from +the command is mailed to the user. This functionality is provided for +compatibility with Vixie cron, but it is also available to scheme +configuration files. The command (with-mail-out action . user) can be +used to direct output from the action (which may be a procedure, list, +or string) into an e-mail to the user. + +In the case that the action is a string, then percentage signs are +processed as per the vixie specifications, and information is piped to +the shell command's standard input. + +@subsection Setting environment variables +@cindex environment variables in scheme +@cindex setting environment variables +@findex append-environment-mods +Also for compatibility with Vixie cron, mcron has the ability to set +environment variables in configuration files. To access this +functionality from a scheme configuration file, use the command +(append-environment-mods name value), where name is the name of an +environment variable, and value is the value put to it. A value of #f +will remove the variable from the environment. + +Note that environment modifications are accumulated as the +configuration file is processed, so when a job actually runs, its +environment will be modified according to the modifications specified +before the job specification in the configuration file. + + +@node Extended Guile examples, Vixie Syntax, Guile Syntax, Syntax +@section Extended Guile examples +@cindex examples, extended guile +@cindex extended guile examples +While Guile gives you flexibility to do anything, and the power to +represent complex requirements succinctly, things are not always as +they seem. The following examples illustrate some pitfalls, and +demonstrate how to code around them. + +@menu +* AT commands:: +* Every second Sunday:: +* Two hours every day:: +* Missing the first appointment:: +* Penultimate day of every month:: +@end menu + +@node AT commands, Every second Sunday, Extended Guile examples, Extended Guile examples +@subsection Synthesizing ``at'' commands +@cindex at command +The current implementation of mcron does not provide for an at command +(a command-line program that allows the user to specify that a job +runs exactly once at a certain time). This can, however, be achieved. + +Suppose the program @code{my-program} needs to be run at midnight +tonight. A Guile script like the following should work. FIXME: TEST +THIS EXAMPLE. + +@example +(define my-program-flag #t) + +(job (lambda (current-time) + (if my-program-flag + (begin + (set! my-program-flag #f) + (next-day-from current-time)) + 99999999)) + (lambda () (system "my-program") + (kill (getppid)))) +@end example + +@node Every second Sunday, Two hours every day, AT commands, Extended Guile examples +@subsection Every second Sunday +@cindex examples, every second sunday +To run @code{my-program} on the second Sunday of every month, a Guile +script like the following should suffice (it is left as an exercise to +the student to understand how this works!). FIXME: TEST THIS EXAMPLE. + +@example +(job (lambda (current-time) + (let* ((next-month (next-month-from current-time)) + (first-day (tm:wday (localtime next-month))) + (second-sunday (if (eqv? first-day 0) + 8 + (- 15 first-day)))) + (+ next-month (* 24 60 60 second-sunday)))) + "my-program") +@end example + + +@node Two hours every day, Missing the first appointment, Every second Sunday, Extended Guile examples +@subsection Two hours every day +@cindex examples, two hours every day +@cindex pitfalls, two hours every day +Surprisingly perhaps, the following will @strong{not} have the desired +effect. + +@example +(job '(next-hour-from (next-day) '(1 2)) + "my-program") +@end example + +Rather than running the my-program program at one o'clock and two +o'clock every day, it will only run it at one o'clock. This is because +each time mcron has to compute the next time to run the command, it +first obtains the next day, and then finds the earliest hour in that +day to run at. Thus, after running the command at one o'clock, the +program first skips forwards to the next midnight (missing the two +o'clock appointment), and then finds the next one o'clock schedule. + +The following simple command is the correct way to specify this +behaviour. + +@example +(job '(next-hour '(1 2)) "my-program") +@end example + + +@node Missing the first appointment, Penultimate day of every month, Two hours every day, Extended Guile examples +@subsection Missing the first appointment +@cindex examples, missing the first appointment +@cindex pitfalls, missing the first appointment +The command + +@example +(job '(next-hour-from (next-day) '(16)) + "my-program") +@end example + +will run @code{my-program} every day at four o'clock in the +afternoon. However, if mcron is started with this script at midday, +the first time the command will run will be four o'clock tomorrow; +today's appointment will be missed (one time only). + +The correct way to specify this requirement is simply + +@example +(job '(next-hour '(16)) + "my-program") +@end example + + +@node Penultimate day of every month, , Missing the first appointment, Extended Guile examples +@subsection Penultimate day of every month +@cindex examples, penultimate day of every month +The following will run the @code{my-program} program on the +second-to-last day of every month. + +@example +(job '(- (next-month-from (next-month)) (* 48 3600)) + "my-program") +@end example + + + +@node Vixie Syntax, , Extended Guile examples, Syntax +@section Vixie +@cindex syntax, vixie +@cindex vixie syntax +@cindex vixie definition +@cindex vixie compatibility +@cindex compatibility, vixie +@emph{NOTE} that this section is definitive. If there is a difference in +behaviour between the mcron program and this part of the manual, then +there is a bug in the program. This section is also copied verbatim +from Paul Dixie'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. + +@cindex thirteenth month of year +@cindex 13th month of year +2. Similarly to the above (but different), months of the year can be +specified in the range 0-12. In the case of mcron (don't know what +Vixie cron did) month 12 will cause the program to wait until January +of the following year (but don't rely on this). + +@cindex shell +@cindex environment variables, shell +@cindex /etc/passwd +3. Somewhere it says that cron sets the SHELL environment variable to +/bin/sh, and elsewhere it implies that the default behaviour is for +the user's default shell to be used to execute commands. Mcron sets +the variable and runs the command in the user's default shell, as +advertised by the /etc/passwd file. + +@menu +* Paul Dixie's copyright:: +* Crontab file:: +* Incompatibilities with old Unices:: +@end menu + + +@node Paul Dixie's copyright, Crontab file, Vixie Syntax, Vixie Syntax +@subsection Paul Dixie's copyright +@cindex copyright, Paul Dixie's +@cindex Paul Dixie's copyright +@quotation +Copyright 1988,1990,1993,1994 by Paul Vixie +All rights reserved + +Distribute freely, except: don't remove my name from the source or +documentation (don't take credit for my work), mark your changes (don't +get me blamed for your possible bugs), don't alter or remove this +notice. May be sold if buildable source is provided to buyer. No +warrantee of any kind, express or implied, is included with this +software; use at your own risk, responsibility for damages (if any) to +anyone resulting from the use of this software rests entirely with the +user. +@end quotation + + + + +@node Crontab file, Incompatibilities with old Unices, Paul Dixie's copyright, Vixie Syntax +@subsection Crontab files. +@cindex crontab file +@cindex vixie crontab file +A @code{crontab} file contains instructions to the @code{cron} daemon +of the general form: ``run this command at this time on this date''. +Each user has their own crontab, and commands in any given crontab +will be executed as the user who owns the crontab. Uucp and News will +usually have their own crontabs, eliminating the need for explicitly +running @code{su} as part of a cron command. + +@cindex comments, vixie-style +Blank lines and leading spaces and tabs are ignored. Lines whose first +non-space character is a pound-sign (#) are comments, and are ignored. +Note that comments are not allowed on the same line as cron commands, since +they will be taken to be part of the command. Similarly, comments are not +allowed on the same line as environment variable settings. + +An active line in a crontab will be either an environment setting or a cron +command. An environment setting is of the form, + +@cindex environment setting, vixie-style +@example +name = value +@end example + +where the spaces around the equal-sign (=) are optional, and any +subsequent non-leading spaces in @code{value} will be part of the +value assigned to @code{name}. The @code{value} string may be placed +in quotes (single or double, but matching) to preserve leading or +trailing blanks. + +@cindex environment variables, SHELL +@cindex environment variables, LOGNAME +@cindex environment variables, HOME +@cindex SHELL environment variable +@cindex LOGNAME environment variable +@cindex HOME environment variable +@cindex /etc/passwd +Several environment variables are set up automatically by the +@code{cron} daemon. SHELL is set to /bin/sh, and LOGNAME and HOME are +set from the /etc/passwd line of the crontab's owner. HOME and SHELL +may be overridden by settings in the crontab; LOGNAME may not. + +@cindex environment variables, USER +@cindex USER environment variable +@cindex BSD +(Another note: the LOGNAME variable is sometimes called USER on BSD systems... +on these systems, USER will be set also.) @footnote{mcron has not been +ported to BSD, so these notes are not relevant.} + +@cindex environment variables, MAILTO +@cindex MAILTO environment variable +In addition to LOGNAME, HOME, and SHELL, @code{cron} will look at +MAILTO if it has any reason to send mail as a result of running +commands in ``this'' crontab. If MAILTO is defined (and non-empty), +mail is sent to the user so named. If MAILTO is defined but empty +(MAILTO=""), no mail will be sent. Otherwise mail is sent to the +owner of the crontab. This option is useful if you decide on +/bin/mail instead of /usr/lib/sendmail as your mailer when you install +cron -- /bin/mail doesn't do aliasing, and UUCP usually doesn't read +its mail. + +The format of a cron command is very much the V7 standard, with a number of +upward-compatible extensions. Each line has five time and date fields, +followed by a user name if this is the system crontab file, +followed by a command. Commands are executed by @code{cron} +when the minute, hour, and month of year fields match the current +time, @strong{and} when at least one of the two day fields (day of month, or day of week) +match the current time (see ``Note'' below). @code{cron} examines cron entries once every minute. +The time and date fields are: + +@cindex vixie time specification fields +@cindex fields, vixie time specification +@multitable @columnfractions .2 .5 +@item Field @tab Allowed values +@item ----- @tab -------------- +@item minute @tab 0-59 +@item hour @tab 0-23 +@item day of month @tab 0-31 +@item month @tab 0-12 (or names, see below) +@item day of week @tab 0-7 (0 or 7 is Sun, or use names) +@end multitable + +A field may be an asterisk (*), which always stands for ``first-last''. + +@cindex ranges in vixie time specifications +Ranges of numbers are allowed. Ranges are two numbers separated +with a hyphen. The specified range is inclusive. For example, +8-11 for an ``hours'' entry specifies execution at hours 8, 9, 10 +and 11. + +@cindex lists in vixie time specifications +Lists are allowed. A list is a set of numbers (or ranges) +separated by commas. Examples: ``1,2,5,9'', ``0-4,8-12''. + +@cindex steps in vixie time specifications +Step values can be used in conjunction with ranges. Following +a range with ``/'' specifies skips of the number's value +through the range. For example, ``0-23/2'' can be used in the hours +field to specify command execution every other hour (the alternative +in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22''). Steps are +also permitted after an asterisk, so if you want to say ``every two +hours'', just use ``*/2''. + +@cindex names in vixie-style time specifications +Names can also be used for the ``month'' and ``day of week'' +fields. Use the first three letters of the particular +day or month (case doesn't matter). Ranges or +lists of names are not allowed. @footnote{Mcron allows any alphabetic +characters after a name, so full names of days or months are also valid.} + +@cindex % character on vixie-style commands +@cindex standard input, vixie-style +The ``sixth'' field (the rest of the line) specifies the command to be +run. +The entire command portion of the line, up to a newline or % +character, will be executed by /bin/sh or by the shell +specified in the SHELL variable of the cronfile. +Percent-signs (%) in the command, unless escaped with backslash +(\\), will be changed into newline characters, and all data +after the first % will be sent to the command as standard +input. + +@cindex day specification, vixie-style +@cindex vixie-style day specification +Note: The day of a command's execution can be specified by two +fields -- day of month, and day of week. If both fields are +restricted (ie, aren't *), the command will be run when +@emph{either} +field matches the current time. For example, + +``30 4 1,15 * 5'' + +would cause a command to be run at 4:30 am on the 1st and 15th of each +month, plus every Friday. + +EXAMPLE CRON FILE + +@example +# use /bin/sh to run commands, no matter what /etc/passwd says +SHELL=/bin/sh +# mail any output to `paul', no matter whose crontab this is +MAILTO=paul +# +# run five minutes after midnight, every day +5 0 * * * $HOME/bin/daily.job >> $HOME/tmp/out 2>&1 +# run at 2:15pm on the first of every month -- output mailed to paul +15 14 1 * * $HOME/bin/monthly +# run at 10 pm on weekdays, annoy Joe +0 22 * * 1-5 mail -s "It's 10pm" joe%Joe,%%Where are your kids?% +23 0-23/2 * * * echo "run 23 minutes after midn, 2am, 4am ..., everyday" +5 4 * * sun echo "run at 5 after 4 every sunday" +@end example + +@node Incompatibilities with old Unices, , Crontab file, Vixie Syntax +@subsection Extensions and incompatibilities. +@cindex incompatibilities with old Unices +@cindex extensions, vixie over old Unices +This section lists differences between Paul Vixie's cron and the +olde-worlde BSD and AT&T programs, for the benefit of system +administrators and users who are upgrading all the way. + +@itemize @bullet +@item +@cindex day 7 +When specifying day of week, both day 0 and day 7 will be considered Sunday. +BSD and AT&T seem to disagree about this. + +@item +Lists and ranges are allowed to co-exist in the same field. "1-3,7-9" would +be rejected by AT&T or BSD cron -- they want to see "1-3" or "7,8,9" ONLY. + +@item +Ranges can include "steps", so "1-9/2" is the same as "1,3,5,7,9". + +@item +Names of months or days of the week can be specified by name. + +@item +Environment variables can be set in the crontab. In BSD or AT&T, the +environment handed to child processes is basically the one from /etc/rc. + +@item +Command output is mailed to the crontab owner (BSD can't do this), can be +mailed to a person other than the crontab owner (SysV can't do this), or the +feature can be turned off and no mail will be sent at all (SysV can't do this +either). + +@end itemize + + +@node Invoking, Index, Syntax, Top +@chapter Detailed invoking +@cindex invoking +@cindex personality +@cindex mcron program +@cindex cron program +@cindex crond program +@cindex crontab program +The program adopts one of three different personalities depending on +the name used to invoke it. In a standard installation, the program is +installed in the system under the names mcron, cron and crontab +(installed SUID). + +The recommended way to invoke the program is via the mcron personality +described in the next section. The program can also be run as cron by +root, and by the SUID program crontab by individual users to gain +backwards compatibility with Vixie cron. However, due to the fact that +this daemon process is shared by, and under control of, all the users +of the system it is possible (though very unlikely) that it may become +unusable, hence the recommendation to use the mcron personality. + +@cindex deprecated, vixie personality +Furthermore, the Vixie personality is considered deprecated by this +author (it offers not a single advantage over the mcron personality, +and bloats the code by a factor of three). It is unlikely that this +personality will ever actually go away, but the program may in future +be split into two distinct parts, and new developments will only take +place in the part which implements the mcron personality. + + + +@menu +* Running mcron:: +* Running cron or crond:: +* Running crontab:: +* Exit codes:: +@end menu + +@node Running mcron, Running cron or crond, Invoking, Invoking +@section Running mcron +@cindex invoking mcron +@cindex mcron options +@cindex mcron arguments +@cindex command line, mcron +@cindex mcron command line +Mcron should be run by the user who wants to schedule his jobs. It may +be made a background job using the facilities of the shell. The basic +command is +@code{mcron [OPTION ...] [file ...]} +which has the effect of reading all the configuration files specified +(subject to the options) and then waiting until it is time to execute +some command. If no files are given on the command line, then mcron +will look in the user's ~/.cron directory. In either case, files which +end in the extension .vixie or .vix will be assumed to contain +Vixie-style crontabs, and files ending .guile or .gle will be assumed +to contain scheme code and will be executed as such. + +The program accepts the following options. + +@table @option +@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 daemon option +@cindex options, daemon +@cindex options, -d +@cindex -d option +@cindex --daemon option +@item -d +@itemx --daemon +With this option the program will detach itself from the controlling +terminal and run as a daemon process. + +@cindex stdin option +@cindex options, stdin +@cindex options, -i +@cindex -i option +@cindex --stdin option +@cindex standard input, configuring from +@cindex configuring from standard input +@item -i (vixie|guile) +@itemx --stdin=(vixie|guile) +This option is used to indicate whether the configuration information +being passed on the standard input is in Vixie format or Guile +format. Guile is the default. + +@cindex -v option +@cindex --version option +@cindex options, -v +@cindex options, version +@item -v +@itemx --version +This option causes a message to be printed on the standard output with +information about the version and copyright for the current program. + +@cindex -h option +@cindex --help option +@cindex options, -h +@cindex options, --help +@item -h +@itemx --help +This causes a short but complete usage message to be displayed on +standard output. + +@end table + +@node Running cron or crond, Running crontab, Running mcron, Invoking +@section Running cron or crond +@cindex cron, invokation +@cindex running cron +@cindex crond, invokation +@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. + +The options which may be used with this program are as follows. + +@table @option + +@cindex -v option +@cindex --version option +@cindex options, -v +@cindex options, version +@item -v +@itemx --version +This option causes a message to be printed on the standard output with +information about the version and copyright for the current program. + +@cindex -h option +@cindex --help option +@cindex options, -h +@cindex options, --help +@item -h +@itemx --help +This causes a short but complete usage message to be displayed on +standard output. + +@end table + +@node Running crontab, Exit codes, Running cron or crond, Invoking +@section Running crontab +@cindex crontab, invoking +@cindex running crontab +This program is run by individual users to inspect or modify their +crontab files. If a change is made to the file, then the root daemon +process will be given a kick, and will immediately read the new +configuration. A warning will be issued to standard output if it +appears that a cron daemon is not running. + +The command is used as + +@code{crontab [-u user] file} + +or + +@code{crontab [-u user] ( -l | -e | -r )} + +Only the root user can use the -u option, to specify the manipulation +of another user's crontab file. In the first instance, the entire +crontab file of the user is replaced with the contents of the +specified file, or standard input if the file is ``-''. + +In the latter case, the program behaves according to which of the +(mutually exclusive) options was given (note that the long options are +an mcron extension). + +@table @option + +@cindex -l option +@cindex list option, crontab +@cindex options, -l +@cindex options, --list +@cindex viewing a crontab +@cindex listing a crontab +@item -l +@itemx --list +Print the user's crontab file to the standard output, and exit. + +@cindex -r option +@cindex remove option +@cindex options, -r +@cindex options, --remove +@cindex deleting a crontab +@cindex removing a crontab +@item -r +@item --remove +Delete the user's crontab file, and exit. + +@cindex -e option +@cindex edit option +@cindex options, -e +@cindex options, --edit +@cindex editing a crontab +@cindex creating a crontab +@item -e +@item --edit +Using the editor specified in the user's VISUAL or EDITOR environment +variables, allow the user to edit his crontab. Once the user exits the +editor, the crontab is checked for parseability, and if it is okay +then it is installed as the user's new crontab and the daemon is +notified that a change has taken place, so that the new file will +become immediately effective. + +@end table + +@node Exit codes, , Running crontab, Invoking +@section Exit codes +@cindex exit codes +@cindex error conditions +@cindex errors +The following are the status codes returned to the operating system +when the program terminates. + +@table @asis +@item 0 +No problems. + +@item 1 +An attempt has been made to start cron but there is already a +/var/run/cron.pid file. If there really is no other cron daemon +running (this does not include invokations of mcron) then you should +remove this file before attempting to run cron. + +@item 2 +In parsing a guile configuration file, a @code{job} command has been +seen but the second argument is neither a procedure, list or +string. This argument is the job's action, and needs to be specified +in one of these forms. + +@item 3 +In parsing a guile configuration file, a @code{job} command has been +seen but the first argument is neither a procedure, list or +string. This argument is the job's next-time specification, and needs +to be specified in one of these forms. + +@item 4 +An attempt to run cron has been made by a user who does not have +permission to access the crontabs in /var/cron/tabs. These files +should be readable only by root, and the cron daemon must be run as +root. + +@item 5 +An attempt to run mcron has been made, but there are no jobs to +schedule! + +@item 6 +The system administrator has blocked this user from using crontab with +the files /var/cron/allow and /var/cron/deny. + +@item 7 +Crontab has been run with more than one of the arguments @code{-l}, +@code{-r}, @code{-e}. These are mutually exclusive options. + +@item 8 +Crontab has been run with the -u option by a user other than +root. Only root is allowed to use this option. + +@item 9 +An invalid vixie-style time specification has been supplied. + +@item 10 +An invalid vixie-style job specification has been supplied. + +@item 11 +A bad line has been seen in /etc/crontab. + +@item 12 +The last component of the name of the program was not one of +@code{mcron}, @code{cron}, @code{crond} or @code{crontab}. + +@item 13 +Either the ~/.cron directory does not exist, or there is a problem +reading the files there. + +@item 14 +There is a problem writing to /var/cron/update. This is probably +because the crontab program is not installed SUID root, as it should +be. + +@item 15 +Crontab has been run without any arguments at all. There is no default +behaviour in this case. + +@item 16 +Cron has been run by a user other than root. + +@end table + + + +@node Index, , Invoking, Top +@unnumbered Index + +@printindex cp + +@bye diff --git a/vixie.scm b/vixie.scm new file mode 100644 index 0000000..2e7df93 --- /dev/null +++ b/vixie.scm @@ -0,0 +1,452 @@ +;; Copyright (C) 2003 Dale Mellor +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +;; USA. + + + +;; This file provides methods for reading a complete Vixie-style configuration +;; file, either from a real file or an already opened port. It also exposes the +;; method for parsing the time-specification part of a Vixie string, so that +;; these can be used to form the next-time-function of a job in a Guile +;; configuration file. + + + +(use-modules (ice-9 regex) (ice-9 rdelim) (srfi srfi-13) (srfi srfi-14)) + + + +;; In Vixie-style time specifications three-letter symbols are allowed to stand +;; for the numbers corresponding to months and days of the week. We deal with +;; this by making a textual substitution early on in the processing of the +;; strings. +;; +;; We start by defining, once and for all, a list of cons cells consisting of +;; regexps which will match the symbols - which allow an arbitrary number of +;; other letters to appear after them (so that the user can optionally complete +;; the month and day names; this is an extension of Vixie) - and the value which +;; is to replace the symbol. +;; +;; The procedure then takes a string, and then for each symbol in the +;; parse-symbols list attempts to locate an instance and replace it with an +;; ASCII representation of the value it stands for. The procedure returns the +;; modified string. (Note that each symbol can appear only once, which meets the +;; Vixie specifications technically but still allows silly users to mess things +;; up). + +(define parse-symbols + (map (lambda (symbol-cell) + (cons (make-regexp (string-append (car symbol-cell) "[[:alpha:]]*") + regexp/icase) + (cdr symbol-cell))) + '(("jan" . "0") ("feb" . "1") ("mar" . "2") ("apr" . "3") + ("may" . "4") ("jun" . "5") ("jul" . "6") ("aug" . "7") + ("sep" . "8") ("oct" . "9") ("nov" . "10") ("dec" . "11") + + ("sun" . "0") ("mon" . "1") ("tue" . "2") ("wed" . "3") + ("thu" . "4") ("fri" . "5") ("sat" . "6") ))) + +(define (vixie-substitute-parse-symbols string) + (for-each (lambda (symbol-cell) + (let ((match (regexp-exec (car symbol-cell) string))) + (if match + (set! string (string-append (match:prefix match) + (cdr symbol-cell) + (match:suffix match)))))) + parse-symbols) + string) + + + +;; A Vixie time specification is made up of a space-separated list of elements, +;; and the elements consist of a comma-separated list of subelements. The +;; procedure below takes a string holding a subelement, which should have no +;; spaces or symbols (see above) in it, and returns a list of all values which +;; that subelement indicates. There are five distinct cases which must be dealt +;; with: [1] a single '*' which returns a list of all values; [2] a '*' followed +;; by a step specifier; [3] a range and step specifier; [4] a range; and [5] a +;; single number. +;; +;; To perform the computation required for the '*' cases, we need to pass the +;; limit of the allowable range for this subelement as the third argument. As +;; days of the month start at 1 while all the other time components start at 0, +;; we must pass the base of the range to deal with this case also. + +(define parse-vixie-subelement-regexp + (make-regexp "^([[:digit:]]+)(-([[:digit:]]+)(/([[:digit:]]+))?)?$")) + +(define (parse-vixie-subelement string base limit) + (if (char=? (string-ref string 0) #\*) + (range base limit (if (> (string-length string) 1) + (string->number (substring string 2)) ;; [2] + 1)) ;; [1] + (let ((match (regexp-exec parse-vixie-subelement-regexp string))) + (cond ((not match) + (display "Error: Bad Vixie-style time specification.\n") + (primitive-exit 9)) + ((match:substring match 5) + (range (string->number (match:substring match 1)) + (+ 1 (string->number (match:substring match 3))) + (string->number (match:substring match 5)))) ;; [3] + ((match:substring match 3) + (range (string->number (match:substring match 1)) + (+ 1 (string->number (match:substring match 3))))) ;; [4] + (else + (list (string->number (match:substring match 1)))))))) ;; [5] + + + +;; A Vixie element contains the entire specification, without spaces or symbols, +;; of the acceptable values for one of the time components (minutes, hours, +;; days, months, week days). Here we break the comma-separated list into +;; subelements, and process each with the procedure above. The return value is a +;; list of all the valid values of all the subcomponents. +;; +;; The second and third arguments are the base and upper limit on the values +;; that can be accepted for this time element. +;; +;; The effect of the 'apply append' is to merge a list of lists into a single +;; list. + +(define (parse-vixie-element string base limit) + (apply append + (map (lambda (sub-element) + (parse-vixie-subelement sub-element base limit)) + (string-tokenize string (char-set-complement (char-set #\,)))))) + + + +;; Consider there are two lists, one of days in the month, the other of days in +;; the week. This procedure returns an augmented list of days in the month with +;; weekdays accounted for. + +(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:year t year) + (let ((first-day (tm:wday (cdr (mktime t))))) + (apply append + mday-list + (map (lambda (wday) + (let ((first (- wday first-day))) + (if (< first 0) (set! first (+ first 7))) + (range (+ 1 first) 32 7))) + wday-list))))) + + + +;; Return the number of days in a month. Fix up a tm object for the zero'th day +;; of the next month, rationalize the object and extract the day. + +(define (days-in-month month year) + (let ((t (localtime 0))) (set-tm:mday t 0) + (set-tm:mon t (+ month 1)) + (set-tm:year t year) + (tm:mday (cdr (mktime t))))) + + + +;; We will be working with a list of time-spec's, one for each element of a time +;; specification (minute, hour, ...). Each time-spec holds three pieces of +;; information: a list of acceptable values for this time component, a procedure +;; to get the component from a tm object, and a procedure to set the component +;; in a tm object. + +(define (time-spec:list time-spec) (vector-ref time-spec 0)) +(define (time-spec:getter time-spec) (vector-ref time-spec 1)) +(define (time-spec:setter time-spec) (vector-ref time-spec 2)) + + + +;; This procedure modifies the time tm object by setting the component referred +;; to by the time-spec object to its next acceptable value. If this value is not +;; greater than the original (because we have wrapped around the top of the +;; acceptable values list), then the function returns #t, otherwise it returns +;; #f. Thus, if the return value is true then it will be necessary for the +;; caller to increment the next coarser time component as well. +;; +;; The first part of the let block is a concession to humanity; the procedure is +;; simply unreadable without all of these aliases. + +(define (increment-time-component time time-spec) + (let* ((time-list (time-spec:list time-spec)) + (getter (time-spec:getter time-spec)) + (setter (time-spec:setter time-spec)) + (next-best (find-best-next (getter time) time-list)) + (wrap-around (eqv? (cdr next-best) 9999))) + (setter time ((if wrap-around car cdr) next-best)) + wrap-around)) + + + +;; There now follows a set of procedures for adjusting an element of time, +;; i.e. taking it to the next acceptable value. In each case, the head of the +;; time-spec-list is expected to correspond to the component of time in +;; question. If the adjusted value wraps around its allowed range, then the next +;; biggest element of time must be adjusted, and so on. + +;; There is no specification allowed for the year component of +;; time. Therefore, if we have to make an adjustment (presumably because a +;; monthly adjustment has wrapped around the top of its range) we can simply +;; go to the next year. + +(define (nudge-year! time) + (set-tm:year time (+ (tm:year time) 1))) + + +;; We nudge the month by finding the next allowable value, and if it wraps +;; around we also nudge the year. The time-spec-list will have time-spec +;; objects for month and weekday. + +(define (nudge-month! time time-spec-list) + (and (increment-time-component time (car time-spec-list)) + (nudge-year! time))) + + +;; Try to increment the day component of the time according to the combination +;; of the mday-list and the wday-list. If this wraps around the range, or if +;; this falls outside the current month (31st February, for example), then +;; bump the month, set the day to zero, and recurse on this procedure to find +;; the next day in the new month. +;; +;; The time-spec-list will have time-spec entries for mday, month, and +;; weekday. + +(define (nudge-day! time time-spec-list) + (if (or (increment-time-component + time + (vector + (interpolate-weekdays (time-spec:list (car time-spec-list)) + (time-spec:list (caddr time-spec-list)) + (tm:mon time) + (tm:year time)) + tm:mday + set-tm:mday)) + (> (tm:mday time) (days-in-month (tm:mon time) (tm:year time)))) + (begin + (nudge-month! time (cdr time-spec-list)) + (set-tm:mday time 0) + (nudge-day! time time-spec-list)))) + + + +;; The hour is bumped to the next accceptable value, and the day is bumped if +;; the hour wraps around. +;; +;; The time-spec-list holds specifications for hour, mday, month and weekday. + +(define (nudge-hour! time time-spec-list) + (and (increment-time-component time (car time-spec-list)) + (nudge-day! time (cdr time-spec-list)))) + + + +;; The minute is bumped to the next accceptable value, and the hour is bumped +;; if the minute wraps around. +;; +;; The time-spec-list holds specifications for minute, hour, day-date, month +;; and weekday. + +(define (nudge-min! time time-spec-list) + (and (increment-time-component time (car time-spec-list)) + (nudge-hour! time (cdr time-spec-list)))) + + + + +;; This is a procedure which returns a procedure which computes the next time a +;; command should run after the current time, based on the information in the +;; Vixie-style time specification. +;; +;; We start by computing a list of time-spec objects (described above) for the +;; minute, hour, date, month, year and weekday components of the overall time +;; specification [1]. When we create the return procedure, it is this list to +;; 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]. +;; +;; The returned procedure itself:- +;; +;; Starts by obtaining the current broken-down time [4], and fixing it to +;; ensure that it is an acceptable value, as follows. Each component from the +;; biggest down is checked for acceptability, and if it is not acceptable it +;; is bumped to the next acceptable value (this may cause higher components to +;; also be bumped if there is range wrap-around) and all the lower components +;; are set to -1 so that it can successfully be bumped up to zero if this is +;; an allowed value. The -1 value will be bumped up subsequently to an allowed +;; value [5]. +;; +;; Once it has been asserted that the current time is acceptable, or has been +;; adjusted to one minute before the next acceptable time, the minute +;; component is then bumped to the next acceptable time, which may ripple +;; through the higher components if necessary [6]. We now have the next time +;; the command needs to run. +;; +;; The new time is then converted back into a UNIX time, and returned [7]. + +(define (parse-vixie-time string) + (let* ((tokens (string-tokenize (vixie-substitute-parse-symbols string))) + (time-spec-list + (map-in-order (lambda (x) (vector (parse-vixie-element + (list-ref tokens (vector-ref x 0)) + (vector-ref x 1) + (vector-ref x 2)) + (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 ) + #( 2 1 32 ,tm:mday ,set-tm:mday ) + #( 3 0 12 ,tm:mon ,set-tm:mon ) + #( 4 0 7 ,tm:wday ,set-tm:wday ))))) ;; [1] + + (vector-set! (car (last-pair time-spec-list)) + 0 + (map (lambda (time-spec) + (if (eqv? time-spec 7) 0 time-spec)) + (vector-ref (car (last-pair time-spec-list)) 0))) ;; [2] + + (lambda (current-time) ;; [3] + (let ((time (localtime current-time))) ;; [4] + + (if (not (member (tm:mon time) + (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)))) + (begin + (nudge-day! time (cddr time-spec-list)) + (set-tm:hour time -1) + (set-tm:min time -1))) + (if (not (member (tm:hour time) + (time-spec:list (cadr time-spec-list)))) + (begin + (nudge-hour! time (cdr time-spec-list)) + (set-tm:min time -1))) ;; [5] + + (set-tm:sec time 0) + (nudge-min! time time-spec-list) ;; [6] + + (car (mktime time)))))) ;; [7] + + + + +;; A line in a Vixie-style crontab file which gives a command specification +;; carries two pieces of information: a time specification consisting of five +;; space-separated items, and a command which is also separated from the time +;; specification by a space. The line is broken into the two components, and the +;; job procedure run to add the two pieces of information to the job list (this +;; will in turn use the above function to turn the time specification into a +;; function for computing future run times of the command). + +(define parse-user-vixie-line-regexp + (make-regexp "^[[:space:]]*(([^[:space:]]+[[:space:]]+){5})(.*)$")) + +(define (parse-user-vixie-line line) + (let ((match (regexp-exec parse-user-vixie-line-regexp line))) + (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)))))) + + + +;; The case of reading a line from /etc/crontab is similar to above but the user +;; ID appears in the sixth field, before the action. + +(define parse-system-vixie-line-regexp + (make-regexp (string-append "^[[:space:]]*(([^[:space:]]+[[:space:]]+){5})" + "([[:alpha:]][[:alnum:]_]*)[[:space:]]+(.*)$"))) + +(define (parse-system-vixie-line line) + (let ((match (regexp-exec parse-user-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))) + (job (match:substring match 1) + (lambda () (with-mail-out (match:substring match 4) + (passwd:name configuration-user)))))) + + + + +;; The next procedure reads an entire Vixie-style file. For each line in the +;; file there are three possibilities (after continuation lines have been +;; appended): the line is blank or contains only a comment, the line contains an +;; environment modifier which will be handled in environment.scm, or the line +;; contains a command specification in which case we use the procedure above to +;; add an entry to the internal job list. +;; +;; Note that the environment modifications are cleared, so that there is no +;; interference between crontab files (this might lead to unpredictable +;; behaviour because the order in which crontab files are processed, if there is +;; more than one, is generally undefined). + +(define read-vixie-file-comment-regexp + (make-regexp "^[[:space:]]*(#.*)?$")) + + +(define (read-vixie-port port . parse-vixie-line) + (clear-environment-mods) + (if port + (let ((parse-vixie-line + (if (null? parse-vixie-line) parse-user-vixie-line + (car parse-vixie-line)))) + (do ((line (read-line port) (read-line port))) + ((eof-object? line)) + + ;; If the line ends with \, append the next line. + (do () + ((or (< (string-length line) 1) + (not (char=? (string-ref line + (- (string-length line) 1)) + #\\)))) + (let ((next-line (read-line port))) + (if (eof-object? next-line) + (set! next-line "")) + (set! line + (string-append + (substring line 0 (- (string-length line) 1)) + next-line)))) + + ;; Consider the three cases mentioned in the description. + (or (regexp-exec read-vixie-file-comment-regexp line) + (parse-vixie-environment line) + (parse-vixie-line line)))))) + + + +;; If a file cannot be opened, we must silently ignore it because it may have +;; been removed by crontab. However, if the file is there it must be parseable, +;; otherwise the error must be propagated to the caller. + +(define (read-vixie-file file-path . parse-vixie-line) + (let ((port #f)) + (catch #t (lambda () (set! port (open-input-file file-path))) + (lambda (key . args) (set! port #f))) + (if port + (begin + (if (null? parse-vixie-line) + (read-vixie-port port) + (read-vixie-port port (car parse-vixie-line))) + (close port))))) From 62b040336328d99ade41776bd52b1d7cd7298629 Mon Sep 17 00:00:00 2001 From: dale_mellor Date: Sat, 5 Jul 2003 12:13:19 +0000 Subject: [PATCH 002/239] Disabled installation of cron, crontab by default. Fixed up all information files to reflect this. --- BUGS | 6 ++++-- ChangeLog | 24 +++-------------------- NEWS | 16 ++++++++++++++-- README | 51 +++++++++++++++++++++++++++++++------------------ TODO | 10 +++++++--- config.scm.in | 1 - configure.ac | 39 ++++++++++++++++++++----------------- crontab.scm | 19 ++++++++---------- environment.scm | 14 +++++++------- makefile.am | 6 ++++++ mcron.scm | 15 ++++++--------- mcron.texinfo | 6 ++++++ vixie.scm | 9 ++++----- 13 files changed, 118 insertions(+), 98 deletions(-) diff --git a/BUGS b/BUGS index 9eabf92..f501ccb 100644 --- a/BUGS +++ b/BUGS @@ -1,4 +1,4 @@ - -*-text-*- + -*-text-*- * If two users modify their crontabs simultaneously, there will be contention for /var/cron/update between themselves and with the main daemon. @@ -9,5 +9,7 @@ Coordinated Time (UTC). + * As often as not the cron daemon crashes (segfaults) when crontab sends it a - SIGHUP. + SIGHUP. For this reason, the current release does not install cron or + crontab. diff --git a/ChangeLog b/ChangeLog index ae6a219..16394df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,23 +1,7 @@ -2003-06-30 hydro23 > +2003-07-05 Dale Mellor - * mcron.scm: Introduced arbiters to marshall access to updates - structure between main routing and HUP signal action procedure. - - * crontab.scm: When an empty /tmp file is produced for editing, - make it owned by the real user (so he can edit it). - - * mcron.scm, makefile.am: Check explicitly for root user when - running cron personality. Install with only root execute - permission. - - * mcron.scm: Don't create /var/run/cron.pid if the -s option has - been used (this is an undocumented possibility). - - * configure.ac, config.scm.in: Added configure option - --enable-debug to determine whether debugging and traceback should - be turned on. - - * Version bumped 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 @@ -26,5 +10,3 @@ testing... * Version set at 0.99.1 - - diff --git a/NEWS b/NEWS index 5050482..f112b18 100644 --- a/NEWS +++ b/NEWS @@ -1,11 +1,23 @@ -Historic moments in the life of mcron. +Historic moments in the life of mcron. -*-text-*- -Copyright (C) 1992, 1993, 1995-2002 Free Software Foundation, Inc. +Copyright (C) 2003 Dale Mellor See the end for copying conditions. Please send bug reports to dale_mellor@users.sourceforge.net. +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 + working properly). The CVS tag is release_0-99-1 (no branch has been created + for it). + + +Friday, 4th July 2003 + We have been accepted as a Savannah project. A CVS repository and web home + page have been created. We're still waiting for acceptance as a GNU project. + + ---------------------------------------------------------------------- diff --git a/README b/README index 06ccae1..d6e6524 100644 --- a/README +++ b/README @@ -1,38 +1,51 @@ + -*-text-*- + 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. + ---------------------------------------------------------------------- IMPORTANT NOTICES Read the BUGS file. -Do not (yet) install this software on a machine which relies for its functioning -on its current set of crontabs. +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. -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. + Do not (yet) install this software on a machine which relies for its + functioning on its current set of crontabs. -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! + The package must be installed by root. -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. + 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. ---------------------------------------------------------------------- diff --git a/TODO b/TODO index 5f61fcf..b3ca4aa 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,5 @@ + -*-text-*- + Maybe in the near future... * Logging. @@ -16,8 +18,9 @@ There are no plans to actually do the following any time soon... * Full security audit for Vixie mode. - * Move internal functions into a namespace such that configuration files - cannot interfere with mcron itself. + * Move internal functions into a namespace, or provide alternative + environments, such that configuration files cannot interfere with mcron + itself. @@ -28,7 +31,8 @@ Quite likely to happen if version 2.0 ever materializes... * 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). + SIGHUP-/var/cron/update method). (I did already try this but, as with + processes, Guile's use of threads falls over.) diff --git a/config.scm.in b/config.scm.in index f31ac1e..bd62764 100644 --- a/config.scm.in +++ b/config.scm.in @@ -24,4 +24,3 @@ (define config-package-string "@PACKAGE_STRING@") (define config-package-bugreport "@PACKAGE_BUGREPORT@") (define config-sendmail "@SENDMAIL@") -(define config-cat "@CAT@") diff --git a/configure.ac b/configure.ac index f56b111..6c98da4 100644 --- a/configure.ac +++ b/configure.ac @@ -20,30 +20,41 @@ else 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 # Checks for programs. - # AC_CHECK_PROG(CHMOD, chmod, chmod) -AC_CHECK_PROGS(CHMOD, chmod) -if test "x$ac_cv_prog_CHMOD" = "x"; then - AC_MSG_ERROR(chmod not found) -fi AC_CHECK_PROGS(ED, ed) if test "x$ac_cv_prog_ED" = "x"; then AC_MSG_ERROR(ed not found) fi -AC_CHECK_PROGS(CAT, cat) -if test "x$ac_cv_prog_CAT" = "x"; then - AC_MSG_ERROR(cat not found) -fi AC_CHECK_PROGS(WHICH, which) if test "x$ac_cv_prog_WHICH" = "x"; then AC_MSG_ERROR(which not found) fi + # Now find a sendmail or equivalent. AC_CHECK_PROGS(SENDMAIL, sendmail) @@ -66,14 +77,6 @@ fi SENDMAIL=$ac_cv_prog_SENDMAIL -# Checks for libraries. - -# Checks for header files. - -# Checks for typedefs, structures, and compiler characteristics. - -# Checks for library functions. - real_program_prefix=`echo $program_prefix | sed s/NONE//` AC_SUBST(real_program_prefix) diff --git a/crontab.scm b/crontab.scm index 417a900..f7bcf2a 100644 --- a/crontab.scm +++ b/crontab.scm @@ -82,8 +82,7 @@ ;; Iff the real user is root, he can use the -u option to access files of ;; another user. -(define crontab-user - (option-ref options 'user crontab-real-user)) +(define crontab-user (option-ref options 'user crontab-real-user)) @@ -147,12 +146,11 @@ ((option-ref options 'edit #f) (let ((temp-file (string-append "/tmp/crontab." (number->string (getpid)))) - (editor (if (getenv "VISUAL") (getenv "VISUAL") - (if (getenv "EDITOR") (getenv "EDITOR") - "vi")))) - (catch #t - (lambda () (copy-file crontab-file temp-file)) - (lambda (key . args) (with-output-to-file temp-file (lambda () #t)))) + (editor (cond ((getenv "VISUAL") (getenv "VISUAL")) + ((getenv "EDITOR") (getenv "EDITOR")) + (else "vi")))) + (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)) (read-vixie-file temp-file) @@ -167,7 +165,7 @@ ((option-ref options 'remove #f) (catch #t (lambda () (delete-file crontab-file) (hit-server crontab-user)) - (lambda (key . args) #t))) + noop)) ;; In the case of the replace personality we loop over all the arguments on the @@ -194,6 +192,5 @@ ;; used to put out, for total compatibility. (else - (display - "crontab: usage error: file name must be specified for replace.\n") + (display "crontab: usage error: file name must be specified for replace.\n") (primitive-exit 15))) diff --git a/environment.scm b/environment.scm index e4d59a8..f2a8119 100644 --- a/environment.scm +++ b/environment.scm @@ -36,14 +36,14 @@ ;; to control is added at the end of the list. (define (impose-default-environment env-alist passwd-entry) - (append (list (cons "HOME" (passwd:dir passwd-entry)) - (cons "CWD" (passwd:dir passwd-entry)) - (cons "SHELL" (passwd:shell passwd-entry)) - '("TERM" . #f) - '("TERMCAP" . #f)) + (append `(("HOME" . ,(passwd:dir passwd-entry)) + ("CWD" . ,(passwd:dir passwd-entry)) + ("SHELL" . ,(passwd:shell passwd-entry)) + ("TERM" . #f) + ("TERMCAP" . #f)) env-alist - (list (cons "LOGNAME" (passwd:name passwd-entry)) - (cons "USER" (passwd:name passwd-entry))))) + `(("LOGNAME" . ,(passwd:name passwd-entry)) + ("USER" . ,(passwd:name passwd-entry))))) diff --git a/makefile.am b/makefile.am index 00b54ee..4276ebc 100644 --- a/makefile.am +++ b/makefile.am @@ -41,21 +41,27 @@ 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@ ./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@ diff --git a/mcron.scm b/mcron.scm index b41a88b..08842cd 100644 --- a/mcron.scm +++ b/mcron.scm @@ -239,8 +239,7 @@ Report bugs to " config-package-bugreport ".\n (display " /var/run/cron.pid.)\n") (primitive-exit 1))) (if (not (option-ref options 'schedule #f)) - (with-output-to-file "/var/run/cron.pid" - (lambda () #t))) + (with-output-to-file "/var/run/cron.pid" noop)) (setenv "MAILTO" #f) (c-set-cron-signals))) @@ -604,19 +603,17 @@ Report bugs to " config-package-bugreport ".\n (use-modules (srfi srfi-2)) (define (process-files-in-system-directory) -;;; (catch #t (lambda () + (catch #t (lambda () (let ((directory (opendir "/var/cron/tabs"))) (do ((file-name (readdir directory) (readdir directory))) ((eof-object? file-name) (closedir directory)) (and-let* ((user (valid-user file-name))) (set! configuration-user user) (read-vixie-file (string-append "/var/cron/tabs/" - file-name))))) -;;; ) -;;; (lambda (key . args) -;;; (display "You do not have permission to access the system crontabs.\n") -;;; (primitive-exit 4))) - ) + file-name)))))) + (lambda (key . args) + (display "You do not have permission to access the system crontabs.\n") + (primitive-exit 4)))) diff --git a/mcron.texinfo b/mcron.texinfo index 4ceb290..089e5fb 100644 --- a/mcron.texinfo +++ b/mcron.texinfo @@ -10,6 +10,12 @@ 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. diff --git a/vixie.scm b/vixie.scm index 2e7df93..5551518 100644 --- a/vixie.scm +++ b/vixie.scm @@ -416,11 +416,10 @@ ((eof-object? line)) ;; If the line ends with \, append the next line. - (do () - ((or (< (string-length line) 1) - (not (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 "")) From 3a55e7e4684d33241d3e3162f3405d6d7cf37723 Mon Sep 17 00:00:00 2001 From: dale_mellor Date: Sun, 13 Jul 2003 21:45:05 +0000 Subject: [PATCH 003/239] Changed all occurrences of Dixie to Vixie (stupid, stupid error). --- mcron.texinfo | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mcron.texinfo b/mcron.texinfo index 089e5fb..63f4415 100644 --- a/mcron.texinfo +++ b/mcron.texinfo @@ -104,7 +104,7 @@ Extended Guile examples Vixie -* Paul Dixie's copyright:: +* Paul Vixie's copyright:: * Crontab file:: * Incompatibilities with old Unices:: @@ -518,7 +518,7 @@ second-to-last day of every month. @emph{NOTE} that this section is definitive. If there is a difference in behaviour between the mcron program and this part of the manual, then there is a bug in the program. This section is also copied verbatim -from Paul Dixie's documentation for his cron program, and his +from Paul Vixie's documentation for his cron program, and his copyright notice is duly reproduced below. @cindex /etc/crontab @@ -556,16 +556,16 @@ the variable and runs the command in the user's default shell, as advertised by the /etc/passwd file. @menu -* Paul Dixie's copyright:: +* Paul Vixie's copyright:: * Crontab file:: * Incompatibilities with old Unices:: @end menu -@node Paul Dixie's copyright, Crontab file, Vixie Syntax, Vixie Syntax -@subsection Paul Dixie's copyright -@cindex copyright, Paul Dixie's -@cindex Paul Dixie's copyright +@node Paul Vixie's copyright, Crontab file, Vixie Syntax, Vixie Syntax +@subsection Paul Vixie's copyright +@cindex copyright, Paul Vixie's +@cindex Paul Vixie's copyright @quotation Copyright 1988,1990,1993,1994 by Paul Vixie All rights reserved @@ -583,7 +583,7 @@ user. -@node Crontab file, Incompatibilities with old Unices, Paul Dixie's copyright, Vixie Syntax +@node Crontab file, Incompatibilities with old Unices, Paul Vixie's copyright, Vixie Syntax @subsection Crontab files. @cindex crontab file @cindex vixie crontab file From 2c6cfc753d5c4a6116bcf24307371c33f49bcfd1 Mon Sep 17 00:00:00 2001 From: dale_mellor Date: Sun, 20 Jul 2003 15:52:35 +0000 Subject: [PATCH 004/239] All changes from 0.99.1 to 0.99.2 pre-release. --- AUTHORS | 7 ++ BUGS | 25 +++-- ChangeLog | 38 ++++++- NEWS | 15 ++- README | 84 ++++++++------- TODO | 57 ++++++---- configure.ac | 25 +---- crontab.scm | 22 ++-- makefile.am | 16 +-- mcron.c.template | 16 +-- mcron.scm | 270 ++++++++++++++++++++++------------------------- mcron.texinfo | 85 +++++++++------ vixie.scm | 70 ++++++++---- 13 files changed, 399 insertions(+), 331 deletions(-) diff --git a/AUTHORS b/AUTHORS index da27b1c..4d2dae2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -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. diff --git a/BUGS b/BUGS index f501ccb..844c6ce 100644 --- a/BUGS +++ b/BUGS @@ -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. diff --git a/ChangeLog b/ChangeLog index 16394df..e03ef48 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,20 @@ -2003-07-05 Dale Mellor +2003-07-20 Dale Mellor + + * 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 @@ -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. diff --git a/NEWS b/NEWS index f112b18..654811c 100644 --- a/NEWS +++ b/NEWS @@ -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 diff --git a/README b/README index d6e6524..a18f8e3 100644 --- a/README +++ b/README @@ -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. - Do not (yet) install this software on a machine which relies for its - functioning on its current set of crontabs. +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. - The package must be installed by root. +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! - 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. +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. diff --git a/TODO b/TODO index b3ca4aa..a5d5539 100644 --- a/TODO +++ b/TODO @@ -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. + * Develop at and batch modes of operation. - * Make compatibilities with other crons (BSD, SYSV, Solaris, Dillon's, ...) + * Make compatibilities with other crons (BSD, SYSV, Solaris, Dillon's, ...) - * Port to BSD, other operating systems. + * Port to BSD, other operating systems. - * Full security audit for Vixie mode. - - * 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; } diff --git a/mcron.scm b/mcron.scm index 08842cd..eb8c9a0 100644 --- a/mcron.scm +++ b/mcron.scm @@ -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) + (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 '())) - (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)))))) + 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)))) + (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. +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. -@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. +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 diff --git a/vixie.scm b/vixie.scm index 5551518..662a194 100644 --- a/vixie.scm +++ b/vixie.scm @@ -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))))))) From eb50865add48ceccfa38bf4165351dd0418df41f Mon Sep 17 00:00:00 2001 From: dale_mellor Date: Sun, 3 Aug 2003 15:14:54 +0000 Subject: [PATCH 005/239] Broken all functionality out into separate modules. --- BUGS | 6 +- ChangeLog | 14 + README | 14 +- TODO | 27 +- config.scm.in | 10 +- configure.ac | 7 +- crontab.scm | 31 +- environment.scm | 75 ++-- job-specifier.scm | 262 ++++++++++++ main.scm | 419 ++++++++++++++++++ makefile.am | 25 +- makefile.ed | 10 +- mcron-core.scm | 247 +++++++++++ mcron.scm | 825 ------------------------------------ mcron.texinfo | 219 +++++++++- email.scm => redirect.scm | 9 +- vixie-specification.scm | 191 +++++++++ vixie.scm => vixie-time.scm | 135 +----- 18 files changed, 1458 insertions(+), 1068 deletions(-) create mode 100644 job-specifier.scm create mode 100644 main.scm create mode 100644 mcron-core.scm delete mode 100644 mcron.scm rename email.scm => redirect.scm (97%) create mode 100644 vixie-specification.scm rename vixie.scm => vixie-time.scm (73%) diff --git a/BUGS b/BUGS index 844c6ce..f48d605 100644 --- a/BUGS +++ b/BUGS @@ -1,4 +1,8 @@ - -*-text-*- +Copyright (C) 2003 Dale Mellor -*-text-*- +See the end for copying conditions. + + +The currently-known bugs are:- * 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 diff --git a/ChangeLog b/ChangeLog index e03ef48..b6223d3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2003-08-03 Dale Mellor + + * Third cut, fully functional, modular, production quality, still + needs testing... + + * Pulled all functionality into modules, so it can be incorporated + into other programs. + + * Bumped version to 0.99.3. + + 2003-07-20 Dale Mellor * Second cut, now _really_ fully functional (100% Vixie @@ -21,6 +32,9 @@ * First cut, fully functional, production quality code, just needs testing... + * Broken/incomplete Guile prevents vixie compatibility from + working - this has been disabled by default in the configuration. + * Version set at 0.99.1 diff --git a/README b/README index a18f8e3..ca1c3f0 100644 --- a/README +++ b/README @@ -1,8 +1,8 @@ -Copyright (C) 2003 Dale Mellor +Copyright (C) 2003 Dale Mellor -*-text-*- See the end for copying conditions. -This is version 0.99.2 of the mcron program (the second 1.0.0 release +This is version 0.99.3 of the mcron program (the third 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 @@ -44,14 +44,16 @@ m.crontab. 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). +`info mcron' at the command line). Notes for end users, sysadmins, and +developers who wish to incorporate mcron into their own programs are included +here. 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 either via Savannah at +Please send all other bug reports either via Savannah (preferred) at https://savannah.nongnu.org/bugs/?func=addbug&group=mcron -or by electronic mail to: +or else by electronic mail to: dale_mellor@users.sourceforge.net Mcron is free software. See the file COPYING for copying conditions. @@ -59,6 +61,8 @@ 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 diff --git a/TODO b/TODO index a5d5539..e5c0c60 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -Copyright (C) 2003 Dale Mellor +Copyright (C) 2003 Dale Mellor -*-text-*- See the end for copying conditions. @@ -9,12 +9,10 @@ Maybe in the near future... * 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. + * Work out how to give each user his own closure (or environment or module + or continuation) 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. @@ -30,24 +28,17 @@ There are no plans to actually do the following any time soon... -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). +May happen if version 2.0 ever materializes... * 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). - - - -May happen if version 2.0 ever materializes... + daemon (unrelated to, or maybe a major enhancement of, socket used for + communication from crontab process). * 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 - just CGI personality. + crontab-like CGI personality. * GTK+/Bononbo/Gnome2 interface. diff --git a/config.scm.in b/config.scm.in index bd62764..6bd71cb 100644 --- a/config.scm.in +++ b/config.scm.in @@ -20,7 +20,9 @@ ;; Some constants set by the configuration process. -(define config-debug @CONFIG_DEBUG@) -(define config-package-string "@PACKAGE_STRING@") -(define config-package-bugreport "@PACKAGE_BUGREPORT@") -(define config-sendmail "@SENDMAIL@") +(define-module (mcron config)) + +(define-public config-debug @CONFIG_DEBUG@) +(define-public config-package-string "@PACKAGE_STRING@") +(define-public config-package-bugreport "@PACKAGE_BUGREPORT@") +(define-public config-sendmail "@SENDMAIL@") diff --git a/configure.ac b/configure.ac index bbbc115..9b4c2de 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.2, dale_mellor@users.sourceforge.net) +AC_INIT(mcron, 0.99.3, dale_mellor@users.sourceforge.net) AM_INIT_AUTOMAKE @@ -24,6 +24,7 @@ AC_SUBST(CONFIG_DEBUG) AC_PROG_CC GUILE_PROGS GUILE_FLAGS +GUILE_SITE_DIR # Checks for programs. AC_CHECK_PROGS(ED, ed) @@ -34,6 +35,10 @@ AC_CHECK_PROGS(WHICH, which) if test "x$ac_cv_prog_WHICH" = "x"; then AC_MSG_ERROR(which not found) fi +AC_CHECK_PROGS(CP, cp) +if test "x$ac_cv_prog_CP" = "x"; then + AC_MSG_ERROR(cp not found) +fi # Now find a sendmail or equivalent. diff --git a/crontab.scm b/crontab.scm index 2c5152d..266311a 100644 --- a/crontab.scm +++ b/crontab.scm @@ -17,7 +17,7 @@ ;; Apart from the collecting of options and the handling of --help and --version -;; (which are done in the mcron.scm file), this file provides all the +;; (which are done in the main.scm file), this file provides all the ;; functionality of the crontab personality. It is designed to be loaded and run ;; once, and then the calling program can exit and the crontab program will have ;; completed its function. @@ -25,8 +25,7 @@ ;; Procedure to communicate with running cron daemon that a user has modified -;; his crontab. The user name is placed in /var/cron/update, and the process -;; whose PID is held in /var/run/cron.pid is sent a SIGHUP. +;; his crontab. The user name is written to the /var/cron/socket UNIX socket. (define (hit-server user-name) (catch #t (lambda () @@ -74,19 +73,6 @@ -;; Iff the real user is root, he can use the -u option to access files of -;; another user. - -(define crontab-user (option-ref options 'user crontab-real-user)) - - - -;; So now we know which crontab file we will be manipulating. - -(define crontab-file (string-append "/var/cron/tabs/" crontab-user)) - - - ;; Check that no more than one of the mutually exclusive options are being used. (if (> (+ (if (option-ref options 'edit #f) 1 0) @@ -108,6 +94,19 @@ +;; Iff the --user option is given, the crontab-user may be different from the +;; real user. + +(define crontab-user (option-ref options 'user crontab-real-user)) + + + +;; So now we know which crontab file we will be manipulating. + +(define crontab-file (string-append "/var/cron/tabs/" crontab-user)) + + + ;; There are four possible sub-personalities to the crontab personality: list, ;; remove, edit and replace (when the user uses no options but supplies file ;; names on the command line). diff --git a/environment.scm b/environment.scm index f2a8119..b340330 100644 --- a/environment.scm +++ b/environment.scm @@ -17,23 +17,33 @@ -;; This file defines the global variable current-environment-mods, and the -;; procedures append-environment-mods (which is available to user configuration -;; files), clear-environment-mods, modify-environment, and -;; parse-vixie-environment. The idea is that the current-environment-mods is a -;; list of pairs of environment names and values, and represents the cumulated -;; environment settings in a configuration file. When a job definition is seen -;; in a configuration file, the current-environment-mods are copied into the -;; internal job description, and when the job actually runs these environment -;; modifications are applied to the UNIX environment in which the job runs. +;; This file defines the variable current-environment-mods, and the procedures +;; append-environment-mods (which is available to user configuration files), +;; clear-environment-mods and modify-environment. The idea is that the +;; current-environment-mods is a list of pairs of environment names and values, +;; and represents the cumulated environment settings in a configuration +;; file. When a job definition is seen in a configuration file, the +;; current-environment-mods are copied into the internal job description, and +;; when the job actually runs these environment modifications are applied to the +;; UNIX environment in which the job runs. + +(define-module (mcron environment) + #:export (modify-environment + clear-environment-mods + append-environment-mods + get-current-environment-mods-copy)) + + + + ;; The env-alist is an association list of variable names and values. Variables ;; later in the list will take precedence over variables before. We return a ;; fixed-up version in which some variables are given specific default values -;; (which the user can override), and one variable which the user is not allowed -;; to control is added at the end of the list. +;; (which the user can override), and two variables which the user is not +;; allowed to control are added at the end of the list. (define (impose-default-environment env-alist passwd-entry) (append `(("HOME" . ,(passwd:dir passwd-entry)) @@ -66,6 +76,13 @@ +;; Each time a job is added to the system, we take a snapshot of the current set +;; of environment modifiers. + +(define (get-current-environment-mods-copy) + (list-copy current-environment-mods)) + + ;; When we start to parse a new configuration file, we want to start with a ;; fresh environment (actually an umodified version of the pervading mcron @@ -76,46 +93,12 @@ - ;; Procedure to add another environment setting to the alist above. This is used ;; both implicitly by the Vixie parser, and can be used directly by users in ;; scheme configuration files. The return value is purely for the convenience of -;; the parse-vixie-environment procedure below. +;; the parse-vixie-environment in the vixie-specification module (yuk). (define (append-environment-mods name value) (set! current-environment-mods (append current-environment-mods (list (cons name value)))) #t) - - - - -;; Procedure to act on an environment variable specification in a Vixie-style -;; configuration file, by adding an entry to the alist above. Returns #t if the -;; operation was successful, #f if the line could not be interpreted as an -;; environment specification. - -(define parse-vixie-environment-regexp1 - (make-regexp - "^[ \t]*([[:alpha:]_][[:alnum:]_]*)[ \t]*=[ \t]*\"(.*)\"[ \t]*$")) -(define parse-vixie-environment-regexp2 - (make-regexp - "^[ \t]*([[:alpha:]_][[:alnum:]_]*)[ \t]*=[ \t]*\'(.*)\'[ \t]*$")) -(define parse-vixie-environment-regexp3 - (make-regexp - "^[ \t]*([[:alpha:]_][[:alnum:]_]*)[ \t]*=[ \t]*(.*[^ \t])[ \t]*$")) -(define parse-vixie-environment-regexp4 - (make-regexp - "^[ \t]*([[:alpha:]_][[:alnum:]_]*)[ \t]*=[ \t]*$")) - -(use-modules (srfi srfi-2)) - -(define (parse-vixie-environment string) - (let ((match (or (regexp-exec parse-vixie-environment-regexp1 string) - (regexp-exec parse-vixie-environment-regexp2 string) - (regexp-exec parse-vixie-environment-regexp3 string)))) - (if match - (append-environment-mods (match:substring match 1) - (match:substring match 2)) - (and-let* ((match (regexp-exec parse-vixie-environment-regexp4 string))) - (append-environment-mods (match:substring match 1) #f))))) diff --git a/job-specifier.scm b/job-specifier.scm new file mode 100644 index 0000000..3bba9b3 --- /dev/null +++ b/job-specifier.scm @@ -0,0 +1,262 @@ +;; Copyright (C) 2003 Dale Mellor +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +;; USA. + + + +;; This module defines all the functions that can be used by scheme mcron +;; configuration files, namely the procedures for working out next times, the +;; job procedure for registering new jobs (actually a wrapper around the core +;; add-job function), and the procedure for declaring environment modifications. + +(define-module (mcron job-specifier) + #:export (range + next-year-from next-year + next-month-from next-month + next-day-from next-day + next-hour-from next-hour + next-minute-from next-minute + next-second-from next-second + set-configuration-user + set-configuration-time + job + find-best-next) + #:use-module (mcron core) + #:use-module (mcron environment) + #:use-module (mcron vixie-time) + #:re-export (append-environment-mods)) + + + +;; Function (available to user configuration files) which produces a list of +;; values from start up to (but not including) end. An optional step may be +;; supplied, and (if positive) only every step'th value will go into the +;; list. For example, (range 1 6 2) returns '(1 3 5). + +(define (range start end . step) + (let ((step (if (or (null? step) + (<= (car step) 0)) + 1 + (car step)))) + (let loop ((start start)) + (if (>= start end) '() + (cons start + (loop (+ start step))))))) + + + +;; Internal function (not supposed to be used directly in configuration files; +;; it is exported from the module for the convenience of other parts of the +;; mcron implementation) which takes a value and a list of possible next values +;; (all assumed less than 9999). It returns a pair consisting of the smallest +;; element of the list, and the smallest element larger than the current +;; value. If an example of the latter cannot be found, 9999 will be returned. + +(define (find-best-next current next-list) + (let ((current-best (cons 9999 9999))) + (for-each (lambda (allowed-time) + (if (< allowed-time (car current-best)) + (set-car! current-best allowed-time)) + (if (and (> allowed-time current) + (< allowed-time (cdr current-best))) + (set-cdr! current-best allowed-time))) + next-list) + current-best)) + + + +;; Internal function to return the time corresponding to some near future +;; hour. If hour-list is not supplied, the time returned corresponds to the +;; start of the next hour of the day. +;; +;; If the hour-list is supplied the time returned corresponds to the first hour +;; of the day in the future which is contained in the list. If all the values in +;; the list are less than the current hour, then the time returned will +;; correspond to the first hour in the list *on the following day*. +;; +;; ... except that the function is actually generalized to deal with seconds, +;; minutes, etc., in an obvious way :-) +;; +;; Note that value-list always comes from an optional argument to a procedure, +;; so is wrapped up as the first element of a list (i.e. it is a list inside a +;; list). + +(define (bump-time time value-list component higher-component + set-component! set-higher-component!) + (if (null? value-list) + (set-component! time (+ (component time) 1)) + (let ((best-next (find-best-next (component time) (car value-list)))) + (if (eqv? 9999 (cdr best-next)) + (begin + (set-higher-component! time (+ (higher-component time) 1)) + (set-component! time (car best-next))) + (set-component! time (cdr best-next))))) + (car (mktime time))) + + + + +;; Set of configuration methods which use the above general function to bump +;; specific components of time to the next legitimate value. In each case, all +;; the components smaller than that of interest are taken to zero, so that for +;; example the time of the next year will be the time at which the next year +;; actually starts. + +(define (next-year-from current-time . year-list) + (let ((time (localtime current-time))) + (set-tm:mon time 0) + (set-tm:mday time 1) + (set-tm:hour time 0) + (set-tm:min time 0) + (set-tm:sec time 0) + (bump-time time year-list tm:year tm:year set-tm:year set-tm:year))) + +(define (next-month-from current-time . month-list) + (let ((time (localtime current-time))) + (set-tm:mday time 1) + (set-tm:hour time 0) + (set-tm:min time 0) + (set-tm:sec time 0) + (bump-time time month-list tm:mon tm:year set-tm:mon set-tm:year))) + +(define (next-day-from current-time . day-list) + (let ((time (localtime current-time))) + (set-tm:hour time 0) + (set-tm:min time 0) + (set-tm:sec time 0) + (bump-time time day-list tm:mday tm:mon set-tm:mday set-tm:mon))) + +(define (next-hour-from current-time . hour-list) + (let ((time (localtime current-time))) + (set-tm:min time 0) + (set-tm:sec time 0) + (bump-time time hour-list tm:hour tm:mday set-tm:hour set-tm:mday))) + +(define (next-minute-from current-time . minute-list) + (let ((time (localtime current-time))) + (set-tm:sec time 0) + (bump-time time minute-list tm:min tm:hour set-tm:min set-tm:hour))) + +(define (next-second-from current-time . second-list) + (let ((time (localtime current-time))) + (bump-time time second-list tm:sec tm:min set-tm:sec set-tm:min))) + + + +;; The current-action-time is the time a job was last run, the time from which +;; the next time to run a job must be computed. (When the program is first run, +;; this time is set to the configuration time so that jobs run from that moment +;; forwards.) Once we have this, we supply versions of the time computation +;; commands above which implicitly assume this value. + +(define current-action-time 0) + + + +;; We want to provide functions which take a single optional argument (as well +;; as implicitly the current action time), but unlike usual scheme behaviour if +;; the argument is missing we want to act like it is really missing, and if it +;; is there we want to act like it is a genuine argument, not a list of +;; optionals. + +(define (maybe-args function args) + (if (null? args) + (function current-action-time) + (function current-action-time (car args)))) + + + +;; These are the convenience functions we were striving to define for the +;; configuration files. They are wrappers for the next-X-from functions above, +;; but implicitly use the current-action-time for the time argument. + +(define (next-year . args) (maybe-args next-year-from args)) +(define (next-month . args) (maybe-args next-month-from args)) +(define (next-day . args) (maybe-args next-day-from args)) +(define (next-hour . args) (maybe-args next-hour-from args)) +(define (next-minute . args) (maybe-args next-minute-from args)) +(define (next-second . args) (maybe-args next-second-from args)) + + + +;; The default user for running jobs is the current one (who invoked this +;; program). There are exceptions: when cron parses /etc/crontab the user is +;; specified on each individual line; when cron parses /var/cron/tabs/* the user +;; is derived from the filename of the crontab. These cases are dealt with by +;; mutating this variable. Note that the variable is only used at configuration +;; time; a UID is stored with each job and it is that which takes effect when +;; the job actually runs. + +(define configuration-user (getpw (getuid))) +(define configuration-time (current-time)) + +(define (set-configuration-user user) + (set! configuration-user (if (or (string? user) + (integer? user)) + (getpw user) + user))) +(define (set-configuration-time time) (set! configuration-time time)) + + + +;; The job function, available to configuration files for adding a job rule to +;; the system. +;; +;; Here we must 'normalize' the next-time-function so that it is always a lambda +;; function which takes one argument (the last time the job ran) and returns a +;; single value (the next time the job should run). If the input value is a +;; string this is parsed as a Vixie-style time specification, and if it is a +;; list then we arrange to eval it (but note that such lists are expected to +;; ignore the function parameter - the last run time is always read from the +;; current-action-time global variable). A similar normalization is applied to +;; the action. +;; +;; Here we also compute the first time that the job is supposed to run, by +;; finding the next legitimate time from the current configuration time (set +;; right at the top of this program). + +(define (job time-proc action . displayable) + (let ((action (cond ((procedure? action) action) + ((list? action) (lambda () (primitive-eval action))) + ((string? action) (lambda () (system action))) + (else + (display "job: invalid second argument (action; should be lamdba") + (display "function, string or list)\n") + (primitive-exit 2)))) + + (time-proc + (cond ((procedure? time-proc) time-proc) + ((string? time-proc) (parse-vixie-time time-proc)) + ((list? time-proc) (lambda (current-time) + (primitive-eval time-proc))) + (else + + (display "job: invalid first argument (next-time-function; should ") + (display "be function, string or 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))))))) + (add-job (lambda (current-time) + (set! current-action-time current-time) + (time-proc current-time)) + action + displayable + configuration-time + configuration-user))) diff --git a/main.scm b/main.scm new file mode 100644 index 0000000..94cb004 --- /dev/null +++ b/main.scm @@ -0,0 +1,419 @@ +;; Copyright (C) 2003 Dale Mellor +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +;; USA. + + + +;; This is the 'main' routine for the whole system; the top of this file is the +;; global entry point (after the minimal C wrapper, mcron.c.template); to all +;; intents and purposes the program is pure Guile and starts here. +;; +;; This file is built into mcron.c.template by the makefile, which stringifies +;; the whole lot, and escapes quotation marks and escape characters +;; accordingly. Bear this in mind when considering literal multi-line strings. +;; +;; (l0ad "crontab.scm") (sic) is inlined by the makefile. All other +;; functionality comes through modules in .../share/guile/site/mcron/*.scm. + + + +;; Pull in some constants set by the builder (via autoconf) at configuration +;; time. Turn debugging on if indicated. + +(use-modules (mcron config)) +(if config-debug (begin (debug-enable 'debug) + (debug-enable 'backtrace))) + + + +;; To determine the name of the program, scan the first item of the command line +;; backwards for the first non-alphabetic character. This allows names like +;; in.cron to be accepted as an invocation of the cron command. + +(use-modules (ice-9 regex)) + +(define command-name (match:substring (regexp-exec (make-regexp "[[:alpha:]]*$") + (car (command-line))))) + + + +;; We will be doing a lot of testing of the command name, so it makes sense to +;; perform the string comparisons once and for all here. + +(define command-type (cond ((string=? command-name "mcron") 'mcron) + ((or (string=? command-name "cron") + (string=? command-name "crond")) 'cron) + ((string=? command-name "crontab") 'crontab) + (else + (display "The command name is invalid.\n") + (primitive-exit 12)))) + + + +;; There are a different set of options for the crontab personality compared to +;; all the others, with the --help and --version options common to all the +;; personalities. + +(use-modules (ice-9 getopt-long)) + +(define options + (getopt-long (command-line) + (append + (case command-type ('crontab + '((user (single-char #\u) (value #t)) + (edit (single-char #\e) (value #f)) + (list (single-char #\l) (value #f)) + (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) + (or (string=? "vixie" value) + (string=? "guile" value)))))))) + '((version (single-char #\v) (value #f)) + (help (single-char #\h) (value #f)))))) + + + + +;; If the user asked for the version of this program, give it to him and get +;; out. + +(if (option-ref options 'version #f) + (begin + (display (string-append "\n +" command-name " (" config-package-string ")\n +Written by Dale Mellor\n +\n +Copyright (C) 2003 Dale Mellor\n +This is free software; see the source for copying conditions. There is NO\n +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n +")) + (quit))) + + + +;; Likewise if the user requested the help text. + +(if (option-ref options 'help #f) + (begin + (display (string-append " +Usage: " (car (command-line)) +(case command-type ('mcron +" [OPTIONS] [FILES]\n +Run an mcron process according to the specifications in the FILES (`-' for\n +standard input), or use all the files in ~/.cron with .guile or .vixie\n +extensions.\n +\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 mcron\n + -d, --daemon Immediately detach the program from the terminal and\n + run as a daemon process\n + -i, --stdin=(guile|vixie) Format of data passed as standard input\n + (default guile)") + + ('cron +" [OPTIONS]\n +Unless an option is specified, run a cron daemon as a detached process, \n +reading all the information in the users' crontabs and in /etc/crontab.\n +\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\n + -n, --noetc Do not check /etc/crontab for updates (HIGHLY\n + RECOMMENDED).") + + ('crontab + (string-append " [-u user] file\n" + " " (car (command-line)) " [-u user] { -e | -l | -r }\n" + " (default operation is replace, per 1003.2)\n" + " -e (edit user's crontab)\n" + " -l (list user's crontab)\n" + " -r (delete user's crontab)\n"))) + +"\n\n +Report bugs to " config-package-bugreport ".\n +")) + (quit))) + + + +;; This is called from the C front-end whenever a terminal signal is +;; received. We remove the /var/run/cron.pid file so that crontab and other +;; invokations of cron don't get the wrong idea that a daemon is currently +;; running. + +(define (delete-run-file) + (catch #t (lambda () (delete-file "/var/run/cron.pid") + (delete-file "/var/cron/socket")) + noop) + (quit)) + + + +;; 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. +;; +;; Otherwise, clear the MAILTO environment variable so that output from cron +;; jobs is sent to the various users (this may still be overridden in the +;; configuration files), and call the function in the C wrapper to set up +;; terminal signal responses to vector to the procedure above. The PID file will +;; be filled in properly later when we have forked our daemon process (but not +;; done if we are only viewing the schedules). + +(if (eq? command-type 'cron) + (begin + (if (not (eqv? (getuid) 0)) + (begin + (display "This program must be run by the root user (and should ") + (display "have been installed as such).\n") + (primitive-exit 16))) + (if (access? "/var/run/cron.pid" F_OK) + (begin + (display "A cron daemon is already running.\n") + (display " (If you are sure this is not true, remove the file\n") + (display " /var/run/cron.pid.)\n") + (primitive-exit 1))) + (if (not (option-ref options 'schedule #f)) + (with-output-to-file "/var/run/cron.pid" noop)) + (setenv "MAILTO" #f) + (c-set-cron-signals))) + + + +;; Define the functions available to the configuration files. While we're here, +;; we'll get the core loaded as well. + +(use-modules (mcron core) + (mcron job-specifier) + (mcron vixie-specification)) + + + +;; Procedure to slurp the standard input into a string. + +(define (stdin->string) + (with-output-to-string (lambda () (do ((in (read-char) (read-char))) + ((eof-object? in)) + (display in))))) + + + +;; Now we have the procedures in place for dealing with the contents of +;; configuration files, the crontab personality is able to validate such +;; files. If the user requested the crontab personality, we load and run the +;; code here and then get out. + +(if (eq? command-type 'crontab) + (begin + (load "crontab.scm") + (quit))) + + + +;; Procedure which processes any configuration file according to the +;; extension. If a file is not recognized, it is silently ignored (this deals +;; properly with most editors' backup files, for instance). + +(define guile-file-regexp (make-regexp "\\.gui(le)?$")) +(define vixie-file-regexp (make-regexp "\\.vix(ie)?$")) + +(define (process-user-file file-path) + (cond ((string=? file-path "-") + (if (string=? (option-ref options 'stdin "guile") "vixie") + (read-vixie-port (current-input-port)) + (eval-string (stdin->string)))) + ((regexp-exec guile-file-regexp file-path) + (load file-path)) + ((regexp-exec vixie-file-regexp file-path) + (read-vixie-file file-path)))) + + + +;; Procedure to run through all the files in a user's ~/.cron directory (only +;; happens under the mcron personality). + +(define (process-files-in-user-directory) + (catch #t (lambda () + (let* ((dir-path (string-append (passwd:dir (getpw (getuid))) + "/.cron")) + (directory (opendir dir-path))) + (do ((file-name (readdir directory) (readdir directory))) + ((eof-object? file-name) (closedir directory)) + (process-user-file (string-append dir-path + "/" + file-name))))) + (lambda (key . args) + (display "Cannot read files in your ~/.cron directory.\n") + (primitive-exit 13)))) + + + +;; 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. + +(define (valid-user user-name) + (setpwent) + (do ((entry (getpw) (getpw))) + ((or (not entry) + (string=? (passwd:name entry) user-name)) + (endpwent) + entry))) + + + +;; Procedure to process all the files in the crontab directory, making sure that +;; each file is for a legitimate user and setting the configuration-user to that +;; user. In this way, when the job procedure is run on behalf of the +;; configuration files, the jobs are registered with the system with the +;; appropriate user. Note that only the root user should be able to perform this +;; operation, but we leave it to the permissions on the /var/cron/tabs directory +;; to enforce this. + +(use-modules (srfi srfi-2)) ;; For and-let*. + +(define (process-files-in-system-directory) + (catch #t (lambda () + (let ((directory (opendir "/var/cron/tabs"))) + (do ((file-name (readdir directory) (readdir directory))) + ((eof-object? file-name)) + (and-let* ((user (valid-user file-name))) + (set-configuration-user user) + (read-vixie-file (string-append "/var/cron/tabs/" + file-name)))))) + (lambda (key . args) + (display "You do not have permission to access the system crontabs.\n") + (primitive-exit 4)))) + + + +;; 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 +;; passed on the command line, or else all the ones in the user's .cron +;; directory. If we are running under the cron personality, we read the +;; /var/cron/tabs directory and also the /etc/crontab file. + +(case command-type + ('mcron (if (null? (option-ref options '() '())) + (process-files-in-user-directory) + (for-each (lambda (file-path) + (process-user-file file-path)) + (option-ref options '() '())))) + + ('cron (process-files-in-system-directory) + (use-system-job-list) + (read-vixie-file "/etc/crontab" parse-system-vixie-line) + (use-user-job-list) + (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 "root") + (job '(- (next-minute-from (next-minute)) 6) + check-system-crontab + "/etc/crontab update checker."))))) + + + +;; If the user has requested a schedule of jobs that will run, we provide the +;; information here and then get out. +;; +;; Start by determining the number of time points in the future that output is +;; required for. This may be provided on the command line as a parameter to the +;; --schedule option, or else we assume a default of 8. Finally, ensure that the +;; count is some positive integer. + +(and-let* ((count (option-ref options 'schedule #f))) + (set! count (if (eq? count #t) + 8 + (string->number count))) + (display (get-schedule (if (<= count 0) 1 count))) + (quit)) + + + +;; If we are supposed to run as a daemon process (either a --daemon option has +;; been explicitly used, or we are running as cron or crond), detach from the +;; terminal now. If we are running as cron, we can now write the PID file. + +(if (option-ref options 'daemon (eq? command-type 'cron)) + (begin + (if (not (eqv? (primitive-fork) 0)) + (quit)) + (setsid) + (if (eq? command-type 'cron) + (with-output-to-file "/var/run/cron.pid" + (lambda () (display (getpid)) (newline)))))) + + + +;; If we are running as cron or crond, we establish a socket to listen for +;; updates from a crontab program. This is put into fd-list so that we can +;; inform the main wait-run-wait execution loop to listen for incoming messages +;; on this socket. + +(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)))) + + + +;; This function is called whenever a message comes in on the above socket. We +;; read a user name from the socket, dealing with the "/etc/crontab" special +;; case, remove all the user's jobs from the job list, and then re-read the +;; user's updated file. In the special case we drop all the system jobs and +;; re-read the /etc/crontab file. + +(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 + (clear-system-jobs) + (use-system-job-list) + (read-vixie-file "/etc/crontab" parse-system-vixie-line) + (use-user-job-list)) + (let ((user (getpw user-name))) + (remove-user-jobs user) + (set-configuration-user user) + (read-vixie-file (string-append "/var/cron/tabs/" user-name)))))) + + + +;; Now the main loop. Forever execute the run-job-loop procedure in the mcron +;; core, and when it drops out (can only be because a message has come in on the +;; socket) we process the socket request before restarting the loop again. + +(while #t + (run-job-loop fd-list) + (process-update-request)) diff --git a/makefile.am b/makefile.am index 12a2a2b..e5efea0 100644 --- a/makefile.am +++ b/makefile.am @@ -18,15 +18,17 @@ ## Process this file with automake to produce Makefile.in ED = @ED@ +CP = @CP@ MAINTAINERCLEANFILES = configure makefile makefile.in \ install-sh missing mkinstalldirs texinfo.tex INSTALL \ aclocal.m4 compile depcomp COPYING -CLEANFILES = mcron.c +CLEANFILES = mcron.c core.scm -EXTRA_DIST = makefile.ed config.scm mcron.scm vixie.scm environment.scm \ - email.scm crontab.scm mcron.c.template +EXTRA_DIST = makefile.ed main.scm mcron-core.scm vixie-specification.scm \ + crontab.scm environment.scm job-specifier.scm redirect.scm \ + vixie-time.scm mcron.c.template info_TEXINFOS = mcron.texinfo bin_PROGRAMS = mcron @@ -34,8 +36,19 @@ mcron_SOURCES = mcron.c mcron_LDFLAGS = @GUILE_LDFLAGS@ mcron_CFLAGS = @GUILE_CFLAGS@ -mcron.c : config.scm mcron.scm vixie.scm environment.scm email.scm crontab.scm \ - makefile.ed mcron.c.template +moddir = @GUILE_SITE@/mcron +mod_DATA = core.scm environment.scm job-specifier.scm redirect.scm \ + vixie-time.scm vixie-specification.scm config.scm + + +# If you're wondering, the configure script keeps deleting all files with a name +# like core.*, so we have to keep re-making it (I lost a good day's work because +# of this). + +core.scm : mcron-core.scm + $(CP) mcron-core.scm core.scm + +mcron.c : main.scm crontab.scm makefile.ed mcron.c.template @echo 'Building mcron.c...' @$(ED) < makefile.ed > /dev/null 2>&1 @rm -f mcron.escaped.scm > /dev/null 2>&1 @@ -56,6 +69,8 @@ install-exec-hook: $(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 + ./mkinstalldirs -m 'u=rwx,og=rx' @GUILE_SITE@ + ./mkinstalldirs -m 'u=rwx,og=rx' @GUILE_SITE@/mcron uninstall-hook: rm -f $(fpp){cron,crontab}$(EXEEXT) diff --git a/makefile.ed b/makefile.ed index 15fe15d..af1299b 100644 --- a/makefile.ed +++ b/makefile.ed @@ -17,15 +17,7 @@ # # # -e mcron.scm -/\(load "config.scm"\)/d --1r config.scm -/\(load "vixie.scm"\)/d --1r vixie.scm -/\(load "email.scm"\)/d --1r email.scm -/\(load "environment.scm"\)/d --1r environment.scm +e main.scm /\(load "crontab.scm"\)/d -1r crontab.scm %s/\\/\\\\/g diff --git a/mcron-core.scm b/mcron-core.scm new file mode 100644 index 0000000..90e1da9 --- /dev/null +++ b/mcron-core.scm @@ -0,0 +1,247 @@ +;; Copyright (C) 2003 Dale Mellor +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +;; USA. + + + +(define-module (mcron core) + #:use-module (mcron environment) + #:export (add-job + remove-user-jobs + get-schedule + run-job-loop + ;; These three are deprecated and not documented. + use-system-job-list + use-user-job-list + clear-system-jobs) + #:re-export (clear-environment-mods + append-environment-mods)) + + +(use-modules (srfi srfi-1) ;; For remove. + (srfi srfi-2)) ;; For and-let*. + + + +;; The list of all jobs known to the system. Each element of the list is +;; +;; (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 +;; modifications that need making to the UNIX environment before the action is +;; run. The next-time elements is the only one that is modified during the +;; running of a cron process (i.e. all the others are set once and for all at +;; configuration time). +;; +;; The reason we maintain two lists is that jobs in /etc/crontab may be placed +;; in one, and all other jobs go in the other. This makes it possible to remove +;; all the jobs in the first list in one go, and separately we can remove all +;; jobs from the second list which belong to a particular user. This behaviour +;; is required for full vixie compatibility. + +(define system-job-list '()) +(define user-job-list '()) + +(define configuration-source 'user) + +(define (use-system-job-list) (set! configuration-source 'system)) +(define (use-user-job-list) (set! configuration-source 'user)) + + + +;; Convenience functions for getting and setting the elements of a job object. + +(define (job:user job) (vector-ref job 0)) +(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:displayable job) (vector-ref job 4)) +(define (job:next-time job) (vector-ref job 5)) +(define (job:advance-time! job) + (vector-set! job 5 ((job:next-time-function job) (job:next-time job)))) + + + +;; Remove jobs from the user-job-list belonging to this user. + +(define (remove-user-jobs user) + (if (or (string? user) + (integer? user)) + (set! user (getpw user))) + (set! user-job-list + (remove (lambda (job) (eqv? (passwd:uid user) + (passwd:uid (job:user job)))) + user-job-list))) + + + +;; Remove all the jobs on the system job list. + +(define (clear-system-jobs) (set! system-job-list '())) + + + +;; Add a new job with the given specifications to the head of the appropriate +;; jobs list. + +(define (add-job time-proc action displayable configuration-time + configuration-user) + (if (eq? configuration-source 'user) + (set! user-job-list (cons (vector configuration-user + time-proc + action + (get-current-environment-mods-copy) + displayable + (time-proc configuration-time)) + user-job-list)) + (set! system-job-list (cons (vector configuration-user + time-proc + action + (get-current-environment-mods-copy) + displayable + (time-proc configuration-time)) + system-job-list)))) + + + +;; Procedure to locate the jobs in the global job-list with the lowest +;; (soonest) next-times. These are the jobs for which we must schedule the mcron +;; program (under any personality) to next wake up. The return value is a cons +;; cell consisting of the next time (maintained in the next-time variable) and a +;; list of the job entries that are to run at this time (maintained in the +;; next-jobs-list variable). +;; +;; The procedure works by first obtaining the time of the first job on the list, +;; and setting this job in the next-jobs-list. Then for each other entry on the +;; job-list, either the job runs earlier than any other that have been scanned, +;; in which case the next-time and next-jobs-list are re-initialized to +;; accomodate, or the job runs at the same time as the next job, in which case +;; the next-jobs-list is simply augmented with the new job, or else the job runs +;; later than others noted in which case we ignore it for now and continue to +;; recurse the list. + +(define (find-next-jobs) + (let ((job-list (append system-job-list user-job-list))) + + (if (null? job-list) + + '(#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))))) + + + +;; If the user has requested a schedule of jobs that will run, we provide the +;; information here and then get out. +;; +;; Start by determining the number of time points in the future that output is +;; required for. This may be provided on the command line as a parameter to the +;; --schedule option, or else we assume a default of 8. Having determined this +;; count we enter a loop of displaying the next set of jobs to run, artificially +;; forwarding the time to the next time point (instead of waiting for it to +;; occur as we would do in a normal run of mcron), and recurse around the loop +;; count times. + +(define (get-schedule count) + (with-output-to-string + (lambda () + (do ((count count (- count 1))) + ((eqv? count 0)) + (and-let* ((next-jobs (find-next-jobs)) + (time (car next-jobs)) + (date-string (strftime "%c\n" (localtime time)))) + (for-each (lambda (job) (display date-string) + (display (job:displayable job)) + (newline)(newline) + (job:advance-time! job)) + (cdr next-jobs))))))) + + + +;; For proper housekeeping, it is necessary to keep a record of the number of +;; child processes we fork off to run the jobs. + +(define number-children 0) + + + +;; For every job on the list, fork a process to run it (noting the fact by +;; increasing the number-children counter), and in the new process set up the +;; run-time environment exactly as it should be before running the job proper. +;; +;; In the parent, update the job entry by computing the next time the job needs +;; to run. + +(define (run-jobs jobs-list) + (for-each (lambda (job) + (if (eqv? (primitive-fork) 0) + (begin + (setuid (passwd:uid (job:user job))) + (chdir (passwd:dir (job:user job))) + (modify-environment (job:environment job) (job:user job)) + ((job:action job)) + (primitive-exit 0)) + (begin + (set! number-children (+ number-children 1)) + (job:advance-time! job)))) + jobs-list)) + + + +;; Now the main loop. 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 and reap any children (old jobs) that have +;; completed. Repeat ad infinitum. + +(define (run-job-loop . fd-list) + + (call-with-current-continuation (lambda (break) + + (let ((fd-list (if (null? fd-list) '() (car fd-list)))) + + (let loop () + + (let* ((next-jobs (find-next-jobs)) + (next-time (car next-jobs)) + (next-jobs-list (cdr next-jobs)) + (sleep-time (if next-time (- next-time (current-time)) + 2000000000))) + + (and (> sleep-time 0) + (if (not (null? (car (select fd-list '() '() sleep-time)))) + (break))) + + (run-jobs next-jobs-list) + + (do () ((or (<= number-children 0) + (eqv? (car (waitpid WAIT_ANY WNOHANG)) 0))) + (set! number-children (- number-children 1))) + + (loop))))))) diff --git a/mcron.scm b/mcron.scm deleted file mode 100644 index eb8c9a0..0000000 --- a/mcron.scm +++ /dev/null @@ -1,825 +0,0 @@ -;; Copyright (C) 2003 Dale Mellor -;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) -;; any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this program; if not, write to the Free Software -;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -;; USA. - - - -;; This is the 'main' routine for the whole system; the top of this file is the -;; global entry point (after the minimal C wrapper, mcron.c.template). To all -;; intents and purposes the program is pure Guile and starts here. -;; -;; This file is built into mcron.c.template by the makefile, which stringifies -;; the whole lot, and escapes quotation marks and escape characters -;; accordingly. Bear this in mind when considering literal multi-line strings. -;; -;; (load ...)'s are inlined by the makefile. - - -;; Make a note of the time the script started; regardless of how long it takes -;; to initialize things, we will run any job scheduled to run after this exact -;; second. - -(define configuration-time (current-time)) - - - -;; Pull in some constants set by the builder (via autoconf) at configuration -;; time. Turn debugging on if indicated. - -(load "config.scm") -(if config-debug (begin (debug-enable 'debug) - (debug-enable 'backtrace))) - - - -;; To determine the name of the program, scan the first item of the command line -;; backwards for the first non-alphabetic character. This allows names like -;; in.cron to be accepted as an invocation of the cron command. - -(use-modules (ice-9 regex)) - -(define command-name (match:substring (regexp-exec (make-regexp "[[:alpha:]]*$") - (car (command-line))))) - - - -;; We will be doing a lot of testing of the command name, so it makes sense to -;; perform the string comparisons once and for all here. - -(define command-type (cond ((string=? command-name "mcron") 'mcron) - ((or (string=? command-name "cron") - (string=? command-name "crond")) 'cron) - ((string=? command-name "crontab") 'crontab) - (else - (display "The command name is invalid.\n") - (primitive-exit 12)))) - - - -;; There are a different set of options for the crontab personality compared to -;; all the others, with the --help and --version options common to all the -;; personalities. - -(use-modules (ice-9 getopt-long)) - -(define options - (getopt-long (command-line) - (append - (case command-type ('crontab - '((user (single-char #\u) (value #t)) - (edit (single-char #\e) (value #f)) - (list (single-char #\l) (value #f)) - (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) - (or (string=? "vixie" value) - (string=? "guile" value)))))))) - '((version (single-char #\v) (value #f)) - (help (single-char #\h) (value #f)))))) - - - - -;; If the user asked for the version of this program, give it to him and get -;; out. - -(if (option-ref options 'version #f) - (begin - (display (string-append "\n -" command-name " (" config-package-string ")\n -Written by Dale Mellor\n -\n -Copyright (C) 2003 Dale Mellor\n -This is free software; see the source for copying conditions. There is NO\n -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n -")) - (quit))) - - - -;; Likewise if the user requested the help text. - -(if (option-ref options 'help #f) - (begin - (display (string-append " -Usage: " (car (command-line)) -(case command-type ('mcron -" [OPTIONS] [FILES]\n -Run an mcron process according to the specifications in the FILES (`-' for\n -standard input), or use all the files in ~/.cron with .guile or .vixie\n -extensions.\n -\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 mcron\n - -d, --daemon Immediately detach the program from the terminal and\n - run as a daemon process\n - -i, --stdin=(guile|vixie) Format of data passed as standard input\n - (default guile)") - - ('cron -" [OPTIONS]\n -Unless an option is specified, run a cron daemon as a detached process, \n -reading all the information in the users' crontabs and in /etc/crontab.\n -\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\n - -n, --noetc Do not check /etc/crontab for updates (HIGHLY\n - RECOMMENDED).") - - ('crontab - (string-append " [-u user] file\n" - " " (car (command-line)) " [-u user] { -e | -l | -r }\n" - " (default operation is replace, per 1003.2)\n" - " -e (edit user's crontab)\n" - " -l (list user's crontab)\n" - " -r (delete user's crontab)\n"))) - -"\n\n -Report bugs to " config-package-bugreport ".\n -")) - (quit))) - - -;;---------------------------------------------------------------------- -;; Perform setup processing specific to cron, crond personalities. -;;---------------------------------------------------------------------- - -;; This is called from the C front-end whenever a terminal signal is -;; received. We simply remove the /var/run/cron.pid file so that crontab and -;; other invokations of cron don't get the wrong idea that a daemon is currently -;; running. - -(define (delete-run-file) - (catch #t (lambda () (delete-file "/var/run/cron.pid") - (delete-file "/var/cron/socket")) - noop) - (quit)) - - - -;; 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. -;; -;; Otherwise, clear the MAILTO environment variable so that output from cron -;; jobs is sent to the various users (this may still be overridden in the -;; configuration files), and call the function in the C wrapper to set up -;; terminal and hangup signal responses to vector to the two procedures -;; above. The PID file will be filled in properly later when we have forked our -;; daemon process (but not done if we are only viewing the schedules). - -(if (eq? command-type 'cron) - (begin - (if (not (eqv? (getuid) 0)) - (begin - (display "This program must be run by the root user (and should ") - (display "have been installed as such).\n") - (primitive-exit 16))) - (if (access? "/var/run/cron.pid" F_OK) - (begin - (display "A cron daemon is already running.\n") - (display " (If you are sure this is not true, remove the file\n") - (display " /var/run/cron.pid.)\n") - (primitive-exit 1))) - (if (not (option-ref options 'schedule #f)) - (with-output-to-file "/var/run/cron.pid" noop)) - (setenv "MAILTO" #f) - (c-set-cron-signals))) - - - -;;---------------------------------------------------------------------- -;; Define the functions available to the configuration files. -;;---------------------------------------------------------------------- - - -;; Define the with-mail-out command for configuration files to use (directly or -;; indirectly as is the case when we parse vixie-style files). - -(load "email.scm") - - - -;; Function (available to user configuration files) which produces a list of -;; values from start up to (but not including) end. An optional step may be -;; supplied, and (if positive) only every step'th value will go into the -;; list. For example, (range 1 6 2) returns '(1 3 5). - -(define (range start end . step) - (let ((step (if (or (null? step) - (<= (car step) 0)) - 1 - (car step)))) - (let loop ((start start)) - (if (>= start end) '() - (cons start - (loop (+ start step))))))) - - - -;; Internal function (not supposed to be used directly in configuration files) -;; which takes a value and a list of possible next values (all assumed less than -;; 9999). It returns a pair consisting of the smallest element of the list, and -;; the smallest element larger than the current value. If an example of the -;; latter cannot be found, 9999 will be returned. - -(define (find-best-next current next-list) - (let ((current-best (cons 9999 9999))) - (for-each (lambda (allowed-time) - (if (< allowed-time (car current-best)) - (set-car! current-best allowed-time)) - (if (and (> allowed-time current) - (< allowed-time (cdr current-best))) - (set-cdr! current-best allowed-time))) - next-list) - current-best)) - - - -;; Internal function to return the time corresponding to some near future -;; hour. If hour-list is not supplied, the time returned corresponds to the -;; start of the next hour of the day. -;; -;; If the hour-list is supplied the time returned corresponds to the first hour -;; of the day in the future which is contained in the list. If all the values in -;; the list are less than the current hour, then the time returned will -;; correspond to the first hour in the list *on the following day*. -;; -;; ... except that the function is actually generalized to deal with seconds, -;; minutes, etc., in an obvious way :-) -;; -;; Note that value-list always comes from an optional argument to a procedure, -;; so is wrapped up as the first element of a list (i.e. it is a list inside a -;; list). - -(define (bump-time time value-list component higher-component - set-component! set-higher-component!) - (if (null? value-list) - (set-component! time (+ (component time) 1)) - (let ((best-next (find-best-next (component time) (car value-list)))) - (if (eqv? 9999 (cdr best-next)) - (begin - (set-higher-component! time (+ (higher-component time) 1)) - (set-component! time (car best-next))) - (set-component! time (cdr best-next))))) - (car (mktime time))) - - - - -;; Set of configuration methods which use the above general function to bump -;; specific components of time to the next legitimate value. In each case, all -;; the components smaller than that of interest are taken to zero, so that for -;; example the time of the next year will be the time at which the next year -;; actually starts. - -(define (next-year-from current-time . year-list) - (let ((time (localtime current-time))) - (set-tm:mon time 0) - (set-tm:mday time 1) - (set-tm:hour time 0) - (set-tm:min time 0) - (set-tm:sec time 0) - (bump-time time year-list tm:year tm:year set-tm:year set-tm:year))) - -(define (next-month-from current-time . month-list) - (let ((time (localtime current-time))) - (set-tm:mday time 1) - (set-tm:hour time 0) - (set-tm:min time 0) - (set-tm:sec time 0) - (bump-time time month-list tm:mon tm:year set-tm:mon set-tm:year))) - -(define (next-day-from current-time . day-list) - (let ((time (localtime current-time))) - (set-tm:hour time 0) - (set-tm:min time 0) - (set-tm:sec time 0) - (bump-time time day-list tm:mday tm:mon set-tm:mday set-tm:mon))) - -(define (next-hour-from current-time . hour-list) - (let ((time (localtime current-time))) - (set-tm:min time 0) - (set-tm:sec time 0) - (bump-time time hour-list tm:hour tm:mday set-tm:hour set-tm:mday))) - -(define (next-minute-from current-time . minute-list) - (let ((time (localtime current-time))) - (set-tm:sec time 0) - (bump-time time minute-list tm:min tm:hour set-tm:min set-tm:hour))) - -(define (next-second-from current-time . second-list) - (let ((time (localtime current-time))) - (bump-time time second-list tm:sec tm:min set-tm:sec set-tm:min))) - - - -;; The current-action-time is the time a job was last run, the time from which -;; the next time to run a job must be computed. (When the program is first run, -;; this time is set to the configuration time so that jobs run from that moment -;; forwards.) Once we have this, we supply versions of the time computation -;; commands above which implicitly assume this value. - -(define current-action-time configuration-time) - - - -;; We want to provide functions which take a single optional argument (as well -;; as implicitly the current action time), but unlike usual scheme behaviour if -;; the argument is missing we want to act like it is really missing, and if it -;; is there we want to act like it is a genuine argument, not a list of -;; optionals. - -(define (maybe-args function args) - (if (null? args) - (function current-action-time) - (function current-action-time (car args)))) - - - -;; These are the convenience functions we were striving to define for the -;; configuration files. They are wrappers for the next-X-from functions above, -;; but implicitly use the current-action-time for the time argument. - -(define (next-year . args) (maybe-args next-year-from args)) -(define (next-month . args) (maybe-args next-month-from args)) -(define (next-day . args) (maybe-args next-day-from args)) -(define (next-hour . args) (maybe-args next-hour-from args)) -(define (next-minute . args) (maybe-args next-minute-from args)) -(define (next-second . args) (maybe-args next-second-from args)) - - - -;; The list of all jobs known to the system. Each element of the list is -;; -;; (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 -;; modifications that need making to the UNIX environment before the action is -;; run. The next-time elements is the only one that is modified during the -;; running of a cron process (i.e. all the others are set once and for all at -;; configuration time). - -(define system-job-list '()) -(define user-job-list '()) - - - -;; Convenience functions for getting and setting the elements of a job object. - -(define (job:user job) (vector-ref job 0)) -(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: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))) - - - -;; Introduce the definition of an environment object, and provide methods for -;; its manipulation and application to the environment in which we run a job. - -(load "environment.scm") - - - -;; Introduce functions which can be used directly in configuration files or -;; indirectly to parse vixie-style time specification strings and manufacture -;; corresponding next-time functions like the ones above. - -(load "vixie.scm") - - - -;; The default user for running jobs is the current one (who invoked this -;; program). There are exceptions: when cron parses /etc/crontab the user is -;; specified on each individual line; when cron parses /var/cron/tabs/* the user -;; is derived from the filename of the crontab. These cases are dealt with by -;; mutating this variable. Note that the variable is only used at configuration -;; time; a UID is stored with each job and it is that which takes effect when -;; the job actually runs. - -(define configuration-user (getpw (getuid))) - - - -;; The job function, available to configuration files for adding a job rule to -;; the system. -;; -;; Here we must 'normalize' the next-time-function so that it is always a lambda -;; function which takes one argument (the last time the job ran) and returns a -;; single value (the next time the job should run). If the input value is a -;; string this is parsed as a Vixie-style time specification, and if it is a -;; list then we arrange to eval it (but note that such lists are expected to -;; ignore the function parameter - the last run time is always read from the -;; current-action-time global variable). A similar normalization is applied to -;; the action. -;; -;; Here we also compute the first time that the job is supposed to run, by -;; finding the next legitimate time from the current configuration time (set -;; right at the top of this program). -;; -;; Note that the new job is added at the front of the job-list (this is -;; 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 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))) - (else - (display "job: invalid second argument (action; should be lamdba") - (display "function, string or list)\n") - (primitive-exit 2)))) - - (time-proc - (cond ((procedure? time-proc) time-proc) - ((string? time-proc) (parse-vixie-time time-proc)) - ((list? time-proc) (lambda (dummy) - (primitive-eval time-proc))) - (else - - (display "job: invalid first argument (next-time-function; should ") - (display "be function, string or 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))))) - - - -;;---------------------------------------------------------------------- -;; End of definition of procedures for configuration files. -;;---------------------------------------------------------------------- - - - -;; Procedure to slurp the standard input into a string. - -(define (stdin->string) - (with-output-to-string (lambda () (do ((in (read-char) (read-char))) - ((eof-object? in)) - (display in))))) - - - -;; Now we have the procedures in place for dealing with the contents of -;; configuration files, the crontab personality is able to validate such -;; files. If the user requested the crontab personality, we load and run the -;; code here and then get out. - -(if (eq? command-type 'crontab) - (begin - (load "crontab.scm") - (quit))) - - - -;;---------------------------------------------------------------------- -;; Procedures for effecting the configuration process itself. -;;---------------------------------------------------------------------- - - -;; Procedure which processes any configuration file according to the -;; extension. If a file is not recognized, it is silently ignored (this deals -;; properly with most editors' backup files, for instance). - -(define guile-file-regexp (make-regexp "\\.gui(le)?$")) -(define vixie-file-regexp (make-regexp "\\.vix(ie)?$")) - -(define (process-user-file file-path) - (cond ((string=? file-path "-") - (if (string=? (option-ref options 'stdin "guile") "vixie") - (read-vixie-port (current-input-port)) - (eval-string (stdin->string)))) - ((regexp-exec guile-file-regexp file-path) - (load file-path)) - ((regexp-exec vixie-file-regexp file-path) - (read-vixie-file file-path)))) - - - -;; Procedure to run through all the files in a user's ~/.cron directory (only -;; happens under the mcron personality). - -(define (process-files-in-user-directory) - (catch #t (lambda () - (let* ((dir-path (string-append (passwd:dir configuration-user) - "/.cron")) - (directory (opendir dir-path))) - (do ((file-name (readdir directory) (readdir directory))) - ((eof-object? file-name) (closedir directory)) - (process-user-file (string-append dir-path - "/" - file-name))))) - (lambda (key . args) - (display "Cannot read files in your ~/.cron directory.\n") - (primitive-exit 13)))) - - - -;; 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. - -(define (valid-user user-name) - (setpwent) - (do ((entry (getpw) (getpw))) - ((or (not entry) - (string=? (passwd:name entry) user-name)) - (endpwent) - entry))) - - - -;; Procedure to process all the files in the crontab directory, making sure that -;; each file is for a legitimate user and setting the configuration-user to that -;; user. In this way, when the job procedure is run on behalf of the -;; configuration files, the jobs are registered with the system with the -;; appropriate user. Note that only the root user should be able to perform this -;; operation, but we leave it to the permissions on the /var/cron/tabs directory -;; to enforce this. - -(use-modules (srfi srfi-2)) - -(define (process-files-in-system-directory) - (catch #t (lambda () - (let ((directory (opendir "/var/cron/tabs"))) - (do ((file-name (readdir directory) (readdir directory))) - ((eof-object? file-name)) - (and-let* ((user (valid-user file-name))) - (set! configuration-user user) - (read-vixie-file (string-append "/var/cron/tabs/" - file-name)))))) - (lambda (key . args) - (display "You do not have permission to access the system crontabs.\n") - (primitive-exit 4)))) - - - -;; 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 -;; passed on the command line, or else all the ones in the user's .cron -;; directory. If we are running under the cron personality, we read the -;; /var/cron/tabs directory and also the /etc/crontab file. - -(case command-type - ('mcron (if (null? (option-ref options '() '())) - (process-files-in-user-directory) - (for-each (lambda (file-path) - (process-user-file file-path)) - (option-ref options '() '())))) - - ('cron (process-files-in-system-directory) - (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.")))) - - - -;;---------------------------------------------------------------------- -;; End of configuration section. -;; -;; Now the main execution loop. -;;---------------------------------------------------------------------- - - - -;; Procedure to locate the jobs in the global job-list with the lowest -;; (soonest) next-times. These are the jobs for which we must schedule the mcron -;; program (under any personality) to next wake up. The return value is a cons -;; cell consisting of the next time (maintained in the next-time variable) and a -;; list of the job entries that are to run at this time (maintained in the -;; next-jobs-list variable). -;; -;; The procedure works by first obtaining the time of the first job on the list, -;; and setting this job in the next-jobs-list. Then for each other entry on the -;; job-list, either the job runs earlier than any other that have been scanned, -;; in which case the next-time and next-jobs-list are re-initialized to -;; accomodate, or the job runs at the same time as the next job, in which case -;; the next-jobs-list is simply augmented with the new job, or else the job runs -;; later than others noted in which case we ignore it for now and continue to -;; recurse the list. - -(define (find-next-jobs) - (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))))) - - - -;; If the user has requested a schedule of jobs that will run, we provide the -;; information here and then get out. -;; -;; Start by determining the number of time points in the future that output is -;; required for. This may be provided on the command line as a parameter to the -;; --schedule option, or else we assume a default of 8. Having determined this -;; count we enter a loop of displaying the next set of jobs to run, artificially -;; forwarding the time to the next time point (instead of waiting for it to -;; occur as we would do in a normal run of mcron), and recurse around the loop -;; count times. - -(and-let* ((count (option-ref options 'schedule #f))) - (set! count (if (eq? count #t) - 8 - (string->number count))) - (if (<= count 0) (set! count 1)) - (do ((count count (- count 1))) - ((eqv? count 0)) - (let* ((next-jobs (find-next-jobs)) - (date-string (strftime "%c\n" (localtime (car next-jobs))))) - (for-each (lambda (job) (display date-string) - (display (job:displayable job)) - (newline)(newline) - (job:advance-time! job)) - (cdr next-jobs)))) - (quit)) - - - -;; For proper housekeeping, it is necessary to keep a record of the number of -;; child processes we fork off to run the jobs. - -(define number-children 0) - - - -;; For every job on the list, fork a process to run it (noting the fact by -;; increasing the number-children counter), and in the new process set up the -;; run-time environment exactly as it should be before running the job proper. -;; -;; In the parent, update the job entry by computing the next time the job needs -;; to run. - -(define (run-jobs jobs-list) - (for-each (lambda (job) - (if (eqv? (primitive-fork) 0) - (begin - (setuid (passwd:uid (job:user job))) - (chdir (passwd:dir (job:user job))) - (modify-environment (job:environment job) (job:user job)) - ((job:action job)) - (primitive-exit 0)) - (begin - (set! number-children (+ number-children 1)) - (set! current-action-time (job:next-time job)) - (job:advance-time! job)))) - jobs-list)) - - - -;; If we are supposed to run as a daemon process (either a --daemon option has -;; been explicitly used, or we are running as cron or crond), detach from the -;; terminal now. If we are running as cron, we can now write the PID file. - -(if (option-ref options 'daemon (eq? command-type 'cron)) - (begin - (if (not (eqv? (primitive-fork) 0)) - (quit)) - (setsid) - (if (eq? command-type 'cron) - (with-output-to-file "/var/run/cron.pid" - (lambda () (display (getpid)) (newline)))))) - - - -(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. - -(use-modules (srfi srfi-1)) - -(let main-loop () - - ;; Compute the amount of time that we must sleep until the next job is due to - ;; run. - - (let* ((next-jobs (find-next-jobs)) - (next-time (car next-jobs)) - (next-jobs-list (cdr next-jobs)) - (sleep-time (if next-time (- next-time (current-time)) - #f))) - - (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))) - - (main-loop)) diff --git a/mcron.texinfo b/mcron.texinfo index 6f7ca24..1eef0e7 100644 --- a/mcron.texinfo +++ b/mcron.texinfo @@ -7,9 +7,6 @@ @syncodeindex fn cp @copying -This file documents the @code{mcron} command for running jobs at -scheduled times. - Copyright (C) 2003 Dale Mellor This is free software. See the source files for the terms of the copyright. @@ -54,7 +51,7 @@ by the Foundation. @page @vskip 0pt plus 1fill -@insertcopying +@c @insertcopying @end titlepage @@ -64,7 +61,10 @@ by the Foundation. @node Top, Introduction, (dir), (dir) @top mcron -@insertcopying +This file documents the @code{mcron} command (Mellor's cron) for +running jobs at scheduled times. + +@c @insertcopying @end ifnottex @menu @@ -72,6 +72,7 @@ by the Foundation. * Simple examples:: How to use mcron 99.9% of the time. * Syntax:: All the possibilities for configuring cron jobs. * Invoking:: What happens when you run the mcron command. +* Guile modules:: Incorporating mcron into another Guile program. * Index:: The complete index. @detailmenu @@ -109,6 +110,14 @@ Detailed invoking * Running crontab:: * Exit codes:: +Guile modules + +* The core module:: The job list and execution loop. +* The redirect module:: Sending output of jobs to a mail box. +* The vixie-time module:: Parsing vixie-style time specifications. +* The job-specifier module:: All commands for scheme configuration files. +* The vixie-specification module:: Commands for reading vixie-style crontabs. + @end detailmenu @end menu @@ -766,7 +775,7 @@ either). @end itemize -@node Invoking, Index, Syntax, Top +@node Invoking, Guile modules, Syntax, Top @chapter Detailed invoking @cindex invoking @cindex personality @@ -1022,6 +1031,8 @@ become immediately effective. @end table + + @node Exit codes, , Running crontab, Invoking @section Exit codes @cindex exit codes @@ -1107,7 +1118,201 @@ Cron has been run by a user other than root. -@node Index, , Invoking, Top +@node Guile modules, Index, Invoking, Top +@chapter Guile modules +Some of the key parts of mcron are implemented as modules so they can +be incorporated into other Guile programs, or even into C-sourced +programs if they are linked against libguile. + +It may be, for example, that a program needs to perform house-keeping +functions at certain times of the day, in which case it can spawn +(either fork or thread) a sub-process which uses a built-in +mcron. Another example may be a program which must sleep until some +non-absolute time specified on the Gregorian calendar (the first day +of next week, for example). Finally, it may be the wish of the user to +provide a program with the functionality of mcron plus a bit extra. + +The core module maintains mcron's internal job lists, and provides the +main wait-run-wait loop that is mcron's main function. It also +introduces the facilities for accumulating a set of environment +modifiers, which take effect when jobs run. + +@menu +* The core module:: The job list and execution loop. +* The redirect module:: Sending output of jobs to a mail box. +* The vixie-time module:: Parsing vixie-style time specifications. +* The job-specifier module:: All commands for scheme configuration files. +* The vixie-specification module:: Commands for reading vixie-style crontabs. +@end menu + +@node The core module, The redirect module, Guile modules, Guile modules +@section The core module +@cindex guile module +@cindex core module +@cindex modules, core + +This module may be used by including @code{(use-modules (mcron core))} +in a program. The main functions are @code{add-job} and +@code{run-job-loop}, which allow a program to create a list of job +specifications to run, and then to initiate the wait-run-wait loop +firing the jobs off at the requisite times. However, before they are +introduced two functions which manipulate the environment that takes +effect when a job runs are defined. + +@cindex environment +The environment is a set of name-value pairs which is built up +incrementally. Each time the @code{add-job} function is called, the +environment modifiers that have been accumulated up to that point are +stored with the new job specification, and when the job actually runs +these name-value pairs are used to modify the run-time environment in +effect. + +@deffn{Scheme procedure} append-environment-mods name value +When a job is run make sure the environment variable @var{name} has +the value @var{value}. +@end deffn + +@deffn{Scheme procedure} clear-environment-mods +This procedure causes all the environment modifiers that have been +specified so far to be forgotten. +@end deffn + +@deffn{Scheme procedure} add-job time-proc action displayable configuration-time configuration-user +This procedure adds a job specification to the list of all jobs to +run. @var{time-proc} should be a procedure taking exactly one argument +which will be a UNIX time. This procedure must compute the next time +that the job should run, and return the result. @var{action} should be +a procedure taking no arguments, and contains the instructions that +actually get executed whenever the job is scheduled to +run. @var{displayable} should be a string, and is only for the use of +humans; it can be anything which identifies or simply gives a clue as +to the purpose or function of this job. @var{configuration-time} is +the time from which the first invokation of this job should be +computed. Finally, @var{configuration-user} should be the passwd entry +for the user under whose personality the job is to run. +@end deffn + +@deffn{Scheme procedure} run-job-loop . fd-list +@cindex file descriptors +@cindex interrupting the mcron loop +This procedure returns only under exceptional circumstances, but +usually loops forever waiting for the next time to arrive when a job +needs to run, running that job, recomputing the next run time, and +then waiting again. However, the wait can be interrupted by data +becoming available for reading on one of the file descriptors in the +fd-list, if supplied. Only in this case will the procedure return to +the calling program, which may then make modifications to the job list +before calling the @code{run-job-loop} procedure again to resume execution of +the mcron core. +@end deffn + +@deffn{Scheme procedure} remove-user-jobs user + +The argument @var{user} should be a string naming a user (his +login name), or an integer UID, or an object representing the user's passwd +entry. All jobs on the current job list that are scheduled to be run +under this personality are removed from the job list. +@end deffn + +@deffn{Scheme procedure} get-schedule count +@cindex schedule of jobs +The argument @var{count} should be an integer value giving the number +of time-points in the future to report that jobs will run as. Note +that this procedure is disruptive; if @code{run-job-loop} is called +after this procedure, the first job to run will be the one after the +last job that was reported in the schedule report. The report itself +is returned to the calling program as a string. +@end deffn + +@node The redirect module, The vixie-time module, The core module, Guile modules +@section The redirect module +@cindex redirect module +@cindex modules, redirect + +This module is introduced to a program with the command +@code{(use-modules (mcron redirect))}. + +This module provides the @code{with-mail-out} function, described +fully in @ref{Guile Syntax}. + +@node The vixie-time module, The job-specifier module, The redirect module, Guile modules +@section The vixie-time module +@cindex vixie-time module +@cindex modules, vixie-time + +This module is introduced to a program by @code{(use-modules (mcron +vixie-time))}. + +This module provides a single method for converting a vixie-style time +specification into a procedure which can be used as the +@code{next-time-function} to the core @code{add-job} procedure, or to +the @code{job-specifier} @code{job} procedure. See @ref{Vixie Syntax} +for full details of the allowed format for the time string. + +@deffn{Scheme procedure} parse-vixie-time time-string +The single argument @var{time-string} should be a string containing a +vixie-style time specification, and the return value is the required +procedure. +@end deffn + + +@node The job-specifier module, The vixie-specification module, The vixie-time module, Guile modules +@section The job-specifier module +@cindex job-specifier module +@cindex modules, job-specifier + +This module is introduced to a program by @code{(use-modules (mcron +job-specifier))}. + +This module provides all the functions available to user's Guile +configuration files, namely @code{range}, @code{next-year-from}, +@code{next-year}, @code{next-month-from}, @code{next-month}, +@code{next-day-from}, @code{next-day}, @code{next-hour-from}, +@code{next-hour}, @code{next-minute-from}, @code{next-minute}, +@code{next-second-from}, @code{next-second}, + and last but not least, @code{job}. See @ref{Guile Syntax} for full + details. + +Once this module is loaded, a scheme configuration file can be used to +put jobs onto the job list simply by @code{load}ing the file. + +@node The vixie-specification module, , The job-specifier module, Guile modules +@section The vixie-specification module +@cindex vixie-specification module +@cindex modules, vixie-specification + +To use this module, put the command @code{(use-modules (mcron +vixie-specification))} into your program. + +This module exports a couple of functions for adding jobs to the +internal job list according to a Vixie-style crontab file. + +@deffn{Scheme procedure} read-vixie-port port . parse-line + +This procedure reads a crontab from the given port, and adds jobs to +the job list accordingly, taking care of environment specifications +and comments which may appear in such a file. + +@var{parse-line} should not normally be used, except that if you are +parsing a (deprecated) @code{/etc/crontab} file with a slightly +modified syntax, you may pass the value @var{parse-system-vixie-line} +as the optional argument. + +@end deffn + +@deffn{Scheme procedure} read-vixie-file name . parse-line + +This procedure attempts to open the named file, and if it fails will +return silently. Otherwise, the behaviour is identical to +@code{read-vixie-port} above. + +@end deffn + +Once this module has been declared in a program, a crontab file can be +used to augment the current job list with a call to +@code{read-vixie-file}. + +@node Index, , Guile modules, Top @unnumbered Index @printindex cp diff --git a/email.scm b/redirect.scm similarity index 97% rename from email.scm rename to redirect.scm index ec300a7..0e10b40 100644 --- a/email.scm +++ b/redirect.scm @@ -16,7 +16,8 @@ ;; USA. -;; This file provides the (with-mail-out action . user) procedure. This + +;; This module provides the (with-mail-out action . user) procedure. This ;; procedure runs the action in a child process, allowing the user control over ;; the input and output (including standard error). The input is governed (only ;; in the case of a string action) by the placing of percentage signs in the @@ -28,6 +29,12 @@ ;; sunk to /dev/null; otherwise output is e-mailed to the address held in the ;; MAILTO variable. +(define-module (mcron redirect) + #:export (with-mail-out) + #:use-module ((mcron config) :select (config-sendmail)) + #:use-module (mcron vixie-time)) + + ;; An action string consists of a sequence of characters forming a command ;; executable by the shell, possibly followed by an non-escaped percentage diff --git a/vixie-specification.scm b/vixie-specification.scm new file mode 100644 index 0000000..89c89f4 --- /dev/null +++ b/vixie-specification.scm @@ -0,0 +1,191 @@ +;; Copyright (C) 2003 Dale Mellor +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +;; USA. + + + +;; This file provides methods for reading a complete Vixie-style configuration +;; file, either from a real file or an already opened port. It also exposes the +;; method for parsing the time-specification part of a Vixie string, so that +;; these can be used to form the next-time-function of a job in a Guile +;; configuration file. + +(define-module (mcron vixie-specification) + #:export (parse-user-vixie-line + parse-system-vixie-line + read-vixie-port + read-vixie-file + check-system-crontab) + #:use-module (mcron core) + #:use-module (mcron job-specifier) + #:use-module (mcron redirect) + #:use-module (mcron vixie-time)) + + +(use-modules (ice-9 regex) (ice-9 rdelim) + (srfi srfi-1) (srfi srfi-2) (srfi srfi-13) (srfi srfi-14)) + + + +;; A line in a Vixie-style crontab file which gives a command specification +;; carries two pieces of information: a time specification consisting of five +;; space-separated items, and a command which is also separated from the time +;; specification by a space. The line is broken into the two components, and the +;; job procedure run to add the two pieces of information to the job list (this +;; will in turn use the above function to turn the time specification into a +;; function for computing future run times of the command). + +(define parse-user-vixie-line-regexp + (make-regexp "^[[:space:]]*(([^[:space:]]+[[:space:]]+){5})(.*)$")) + +(define (parse-user-vixie-line line) + (let ((match (regexp-exec parse-user-vixie-line-regexp line))) + (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))) + (match:substring match 3)))) + + + +;; The case of reading a line from /etc/crontab is similar to above but the user +;; ID appears in the sixth field, before the action. + +(define parse-system-vixie-line-regexp + (make-regexp (string-append "^[[:space:]]*(([^[:space:]]+[[:space:]]+){5})" + "([[:alpha:]][[:alnum:]_]*)[[:space:]]+(.*)$"))) + +(define (parse-system-vixie-line 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))) + (let ((user (match:substring match 3))) + (set-configuration-user user) + (job (match:substring match 1) + (lambda () (with-mail-out (match:substring match 4) + user)) + (match:substring match 4))))) + + + +;; Procedure to act on an environment variable specification in a Vixie-style +;; configuration file, by adding an entry to the alist above. Returns #t if the +;; operation was successful, #f if the line could not be interpreted as an +;; environment specification. + +(define parse-vixie-environment-regexp1 + (make-regexp + "^[ \t]*([[:alpha:]_][[:alnum:]_]*)[ \t]*=[ \t]*\"(.*)\"[ \t]*$")) +(define parse-vixie-environment-regexp2 + (make-regexp + "^[ \t]*([[:alpha:]_][[:alnum:]_]*)[ \t]*=[ \t]*\'(.*)\'[ \t]*$")) +(define parse-vixie-environment-regexp3 + (make-regexp + "^[ \t]*([[:alpha:]_][[:alnum:]_]*)[ \t]*=[ \t]*(.*[^ \t])[ \t]*$")) +(define parse-vixie-environment-regexp4 + (make-regexp + "^[ \t]*([[:alpha:]_][[:alnum:]_]*)[ \t]*=[ \t]*$")) + + +(define (parse-vixie-environment string) + (let ((match (or (regexp-exec parse-vixie-environment-regexp1 string) + (regexp-exec parse-vixie-environment-regexp2 string) + (regexp-exec parse-vixie-environment-regexp3 string)))) + (if match + (append-environment-mods (match:substring match 1) + (match:substring match 2)) + (and-let* ((match (regexp-exec parse-vixie-environment-regexp4 string))) + (append-environment-mods (match:substring match 1) #f))))) + + + + +;; The next procedure reads an entire Vixie-style file. For each line in the +;; file there are three possibilities (after continuation lines have been +;; appended): the line is blank or contains only a comment, the line contains an +;; environment modifier which will be handled in the mcron environment module, +;; or the line contains a command specification in which case we use the +;; procedure above to add an entry to the internal job list. +;; +;; Note that the environment modifications are cleared, so that there is no +;; interference between crontab files (this might lead to unpredictable +;; behaviour because the order in which crontab files are processed, if there is +;; more than one, is generally undefined). + +(define read-vixie-file-comment-regexp + (make-regexp "^[[:space:]]*(#.*)?$")) + + +(define (read-vixie-port port . parse-vixie-line) + (clear-environment-mods) + (if port + (let ((parse-vixie-line + (if (null? parse-vixie-line) parse-user-vixie-line + (car parse-vixie-line)))) + (do ((line (read-line port) (read-line port))) + ((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)) + #\\)) + (let ((next-line (read-line port))) + (if (eof-object? next-line) + (set! next-line "")) + (set! line + (string-append + (substring line 0 (- (string-length line) 1)) + next-line)))) + + ;; Consider the three cases mentioned in the description. + (or (regexp-exec read-vixie-file-comment-regexp line) + (parse-vixie-environment line) + (parse-vixie-line line)))))) + + + +;; If a file cannot be opened, we must silently ignore it because it may have +;; been removed by crontab. However, if the file is there it must be parseable, +;; otherwise the error must be propagated to the caller. + +(define (read-vixie-file file-path . parse-vixie-line) + (let ((port #f)) + (catch #t (lambda () (set! port (open-input-file file-path))) + (lambda (key . args) (set! port #f))) + (if port + (begin + (if (null? parse-vixie-line) + (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))))))) diff --git a/vixie.scm b/vixie-time.scm similarity index 73% rename from vixie.scm rename to vixie-time.scm index 662a194..164a8de 100644 --- a/vixie.scm +++ b/vixie-time.scm @@ -17,17 +17,13 @@ -;; This file provides methods for reading a complete Vixie-style configuration -;; file, either from a real file or an already opened port. It also exposes the -;; method for parsing the time-specification part of a Vixie string, so that -;; these can be used to form the next-time-function of a job in a Guile -;; configuration file. +(define-module (mcron vixie-time) + #:export (parse-vixie-time) + #:use-module (mcron job-specifier)) - -(use-modules (ice-9 regex) (ice-9 rdelim) - (srfi srfi-1) (srfi srfi-13) (srfi srfi-14)) - +(use-modules (srfi srfi-1) (srfi srfi-13) (srfi srfi-14) + (ice-9 regex)) ;; In Vixie-style time specifications three-letter symbols are allowed to stand @@ -358,124 +354,3 @@ (nudge-min! time time-spec-list) ;; [6] (car (mktime time)))))) ;; [7] - - - - -;; A line in a Vixie-style crontab file which gives a command specification -;; carries two pieces of information: a time specification consisting of five -;; space-separated items, and a command which is also separated from the time -;; specification by a space. The line is broken into the two components, and the -;; job procedure run to add the two pieces of information to the job list (this -;; will in turn use the above function to turn the time specification into a -;; function for computing future run times of the command). - -(define parse-user-vixie-line-regexp - (make-regexp "^[[:space:]]*(([^[:space:]]+[[:space:]]+){5})(.*)$")) - -(define (parse-user-vixie-line line) - (let ((match (regexp-exec parse-user-vixie-line-regexp line))) - (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))) - (match:substring match 3)))) - - - -;; The case of reading a line from /etc/crontab is similar to above but the user -;; ID appears in the sixth field, before the action. - -(define parse-system-vixie-line-regexp - (make-regexp (string-append "^[[:space:]]*(([^[:space:]]+[[:space:]]+){5})" - "([[:alpha:]][[:alnum:]_]*)[[:space:]]+(.*)$"))) - -(define (parse-system-vixie-line 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 (getpw (match:substring match 3))) - (job (match:substring match 1) - (lambda () (with-mail-out (match:substring match 4) - (passwd:name configuration-user))) - (match:substring match 4)))) - - - - -;; The next procedure reads an entire Vixie-style file. For each line in the -;; file there are three possibilities (after continuation lines have been -;; appended): the line is blank or contains only a comment, the line contains an -;; environment modifier which will be handled in environment.scm, or the line -;; contains a command specification in which case we use the procedure above to -;; add an entry to the internal job list. -;; -;; Note that the environment modifications are cleared, so that there is no -;; interference between crontab files (this might lead to unpredictable -;; behaviour because the order in which crontab files are processed, if there is -;; more than one, is generally undefined). - -(define read-vixie-file-comment-regexp - (make-regexp "^[[:space:]]*(#.*)?$")) - - -(define (read-vixie-port port . parse-vixie-line) - (clear-environment-mods) - (if port - (let ((parse-vixie-line - (if (null? parse-vixie-line) parse-user-vixie-line - (car parse-vixie-line)))) - (do ((line (read-line port) (read-line port))) - ((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)) - #\\)) - (let ((next-line (read-line port))) - (if (eof-object? next-line) - (set! next-line "")) - (set! line - (string-append - (substring line 0 (- (string-length line) 1)) - next-line)))) - - ;; Consider the three cases mentioned in the description. - (or (regexp-exec read-vixie-file-comment-regexp line) - (parse-vixie-environment line) - (parse-vixie-line line)))))) - - - -;; If a file cannot be opened, we must silently ignore it because it may have -;; been removed by crontab. However, if the file is there it must be parseable, -;; otherwise the error must be propagated to the caller. - -(define (read-vixie-file file-path . parse-vixie-line) - (let ((port #f)) - (catch #t (lambda () (set! port (open-input-file file-path))) - (lambda (key . args) (set! port #f))) - (if port - (begin - (if (null? parse-vixie-line) - (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))))))) From 627e81918e50e7806aace870d1529adf5d75a15d Mon Sep 17 00:00:00 2001 From: dale_mellor Date: Thu, 22 Jan 2004 13:54:21 +0000 Subject: [PATCH 006/239] This is the version 1.0.0 release (many changes have occurred without commiting due to disruption to Savannah, including a skip over the 0.99.4 release). --- ChangeLog | 24 +++++++++ NEWS | 28 ++++++++-- README | 62 ++++++++++++---------- config.scm.in | 7 +++ configure.ac | 88 +++++++++++++++++++++++++++++-- crontab.scm | 14 ++--- environment.scm | 17 +++--- main.scm | 20 +++---- mcron-core.scm | 23 ++++---- mcron.texinfo => mcron.texinfo.in | 26 ++++----- vixie-specification.scm | 2 +- 11 files changed, 230 insertions(+), 81 deletions(-) rename mcron.texinfo => mcron.texinfo.in (98%) diff --git a/ChangeLog b/ChangeLog index b6223d3..d501f35 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2003-12-11 Dale Mellor + + * Modified all auxiliary files to reflect that we are now a GNU + package. + + * Bumped version to 1.0.0. + + +2003-12-07 Dale Mellor + + * configure.ac: Added switches for files and directories used by + mcron: --spool-dir, --socket-file, --allow-file, --deny-file, + --pid-file and --tmp-dir. All the code has been modified to use + these configure options (including the source for the texinfo + manual). + + +2003-12-05 Dale Mellor + + * configure.ac: Added test for guile version >= 1.6.4. + + * bumped version to 0.99.4. + + 2003-08-03 Dale Mellor * Third cut, fully functional, modular, production quality, still diff --git a/NEWS b/NEWS index 654811c..8ee2233 100644 --- a/NEWS +++ b/NEWS @@ -3,7 +3,26 @@ Historic moments in the life of mcron. -*-text-*- Copyright (C) 2003 Dale Mellor See the end for copying conditions. -Please send bug reports to dale_mellor@users.sourceforge.net. +Please send bug reports to bugs-mcron@gnu.org. + + +Friday, 12th December 2003 + Released version 1.0.0 through rdmp.org. No CVS tag has been created. + + +Tuesday, 2nd December 2003 + Mcron is now officially a GNU program. Unfortunately Savannah, the + development environment, has been mauled so an immediate GNU release is not + likely. No CVS tag has been created. + + +Tuesday, 5th August 2003 + Released version 0.99.3. The CVS tag will be release_0-99-3 (no branch). + + +Sunday, 3rd August 2003 + Broken the code into modules (which is not the same as saying the code is + broken ;-) ). Sunday, 20th July 2003 @@ -20,13 +39,14 @@ Sunday, 20th July 2003 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 - working properly). The CVS tag is release_0-99-1 (no branch has been created - for it). + working properly). The CVS tag is release_0-99-1 (no branch has been + created for it). Friday, 4th July 2003 We have been accepted as a Savannah project. A CVS repository and web home - page have been created. We're still waiting for acceptance as a GNU project. + page have been created. We're still waiting for acceptance as a GNU + project. diff --git a/README b/README index ca1c3f0..d2ee900 100644 --- a/README +++ b/README @@ -2,11 +2,11 @@ Copyright (C) 2003 Dale Mellor -*-text-*- See the end for copying conditions. -This is version 0.99.3 of the mcron program (the third 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 +This is version 1.0.0 of the mcron program, and is the first release as part of +the GNU system. It is designed and written by Dale Mellor, and 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,8 +15,8 @@ IMPORTANT NOTICES Read the BUGS file. -Do not (yet) install this software on a machine which relies for its functioning -on its current set of crontabs. +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. @@ -24,41 +24,49 @@ 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. +all old crontabs and make new ones afresh - or else look very carefully at the +options you pass to the package configure script, as follows. + +It is often the case that GNU/Linux distributions and other Unices hacked the +cron daemon to use different directories to those above. You can use configure +options --spool-dir, --socket-file, --allow-file, --deny-file, --pid-file and +--tmp-dir to make mcron behave similarly. Note that, with the exception of +tmp-dir, none of these files or directories should be accessible by ordinary +(non-root) users. 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! +where your old cron was (the binaries cron and crontab will be replaced, but if +your existing system has a binary called crond, you should make this a link +to mcron), and you should be able to continue to use your existing crontabs +without noticing any changes. -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. +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 (or m.crond) and m.crontab. ---------------------------------------------------------------------- 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). Notes for end users, sysadmins, and -developers who wish to incorporate mcron into their own programs are included -here. +After installation, read the info file for full instructions for use (typing +`info mcron' at the command line should suffice). Notes for end users, +sysadmins, and developers who wish to incorporate mcron into their own programs +are included here. 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 either via Savannah (preferred) at - https://savannah.nongnu.org/bugs/?func=addbug&group=mcron -or else by electronic mail to: - dale_mellor@users.sourceforge.net +Please send all other bug reports to bugs-mcron@gnu.org. Other mailing lists you +could subscribe to are help-mcron@gnu.org (for help and advice from the +community, including the author) and info-mcron@gnu.org (for news as it +happens). Mcron is free software. See the file COPYING for copying conditions. -The mcron development home page is at http://www.nongnu.org/mcron. +The mcron development home page is at http://www.gnu.org/software/mcron (also +temporarily at http://rdmp.org/mcron), and can be obtained from +ftp://ftp.gnu.org/mcron (or temporarily from ftp://rdmp.org/mcron). diff --git a/config.scm.in b/config.scm.in index 6bd71cb..2ccbd49 100644 --- a/config.scm.in +++ b/config.scm.in @@ -26,3 +26,10 @@ (define-public config-package-string "@PACKAGE_STRING@") (define-public config-package-bugreport "@PACKAGE_BUGREPORT@") (define-public config-sendmail "@SENDMAIL@") + +(define-public config-spool-dir "@CONFIG_SPOOL_DIR@") +(define-public config-socket-file "@CONFIG_SOCKET_FILE@") +(define-public config-allow-file "@CONFIG_ALLOW_FILE@") +(define-public config-deny-file "@CONFIG_DENY_FILE@") +(define-public config-pid-file "@CONFIG_PID_FILE@") +(define-public config-tmp-dir "@CONFIG_TMP_DIR@") diff --git a/configure.ac b/configure.ac index 9b4c2de..6807c39 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.3, dale_mellor@users.sourceforge.net) +AC_INIT(mcron, 1.0.0, dale_mellor@users.sourceforge.net) AM_INIT_AUTOMAKE @@ -21,12 +21,24 @@ fi AC_SUBST(CONFIG_DEBUG) +AC_PROG_AWK +AC_PROG_EGREP AC_PROG_CC GUILE_PROGS GUILE_FLAGS GUILE_SITE_DIR - + + # Checks for programs. + +AC_CHECK_PROGS(SED, sed) +if test "x$ac_cv_prog_SED" = "x"; then + AC_MSG_ERROR(sed not found) +fi +AC_CHECK_PROGS(HEAD, head) +if test "x$ac_cv_prog_HEAD" = "x"; then + AC_MSG_ERROR(head not found) +fi AC_CHECK_PROGS(ED, ed) if test "x$ac_cv_prog_ED" = "x"; then AC_MSG_ERROR(ed not found) @@ -40,7 +52,18 @@ if test "x$ac_cv_prog_CP" = "x"; then AC_MSG_ERROR(cp not found) fi + +# Check the Guile version. +AC_MSG_CHECKING(for guile version >= 1.6.4) +if [$GUILE --version | $HEAD -1 | $AWK '{print $2}' | \ + $EGREP -q '^(1\.(6\.([4-9]|[1-3][^.])|[7-9]|[1-5][^.])|[2-9])']; then + AC_MSG_RESULT(OK) +else + AC_MSG_ERROR([Sorry, Guile 1.6.4 or greater is needed to run mcron]) +fi + + # Now find a sendmail or equivalent. AC_CHECK_PROGS(SENDMAIL, sendmail) @@ -63,11 +86,70 @@ fi SENDMAIL=$ac_cv_prog_SENDMAIL +# Configure the various files that mcron uses at runtime. + +AC_MSG_CHECKING([which spool directory to use]) +AC_ARG_WITH(spool-dir, + AC_HELP_STRING([--with-spool-dir], + [the crontab spool directory (/var/cron/tabs)]), + CONFIG_SPOOL_DIR=$withval, + CONFIG_SPOOL_DIR=[/var/cron/tabs]) +AC_MSG_RESULT($CONFIG_SPOOL_DIR) +AC_SUBST(CONFIG_SPOOL_DIR) + +AC_MSG_CHECKING([name of socket]) +AC_ARG_WITH(socket-file, + AC_HELP_STRING([--with-socket-file], + [unix pathname for cron socket (/var/cron/socket)]), + CONFIG_SOCKET_FILE=$withval, + CONFIG_SOCKET_FILE=[/var/cron/socket]) +AC_MSG_RESULT($CONFIG_SOCKET_FILE) +AC_SUBST(CONFIG_SOCKET_FILE) + +AC_MSG_CHECKING([name of allow file]) +AC_ARG_WITH(allow-file, + AC_HELP_STRING([--with-allow-file], + [the file of allowed users (/var/cron/allow)]), + CONFIG_ALLOW_FILE=$withval, + CONFIG_ALLOW_FILE=[/var/cron/allow]) +AC_MSG_RESULT($CONFIG_ALLOW_FILE) +AC_SUBST(CONFIG_ALLOW_FILE) + +AC_MSG_CHECKING([name of deny file]) +AC_ARG_WITH(deny-file, + AC_HELP_STRING([--with-deny-file], + [the file of barred users (/var/cron/deny)]), + CONFIG_DENY_FILE=$withval, + CONFIG_DENY_FILE=[/var/cron/deny]) +AC_MSG_RESULT($CONFIG_DENY_FILE) +AC_SUBST(CONFIG_DENY_FILE) + +AC_MSG_CHECKING([name of PID file]) +AC_ARG_WITH(pid-file, + AC_HELP_STRING([--with-pid-file], + [the file to record cron's PID (/var/run/cron.pid)]), + CONFIG_PID_FILE=$withval, + CONFIG_PID_FILE=[/var/run/cron.pid]) +AC_MSG_RESULT($CONFIG_PID_FILE) +AC_SUBST(CONFIG_PID_FILE) + +AC_MSG_CHECKING([directory to hold temporary files]) +AC_ARG_WITH(tmp-dir, + AC_HELP_STRING([--with-tmp-dir], + [directory to hold temporary files (/tmp)]), + CONFIG_TMP_DIR=$withval, + CONFIG_TMP_DIR=[/tmp]) +AC_MSG_RESULT($CONFIG_TMP_DIR) +AC_SUBST(CONFIG_TMP_DIR) + + + + # This is to support `make DESTDIR=...' real_program_prefix=`echo $program_prefix | sed s/NONE//` AC_SUBST(real_program_prefix) -AC_CONFIG_FILES(makefile config.scm) +AC_CONFIG_FILES(makefile config.scm mcron.texinfo) AC_OUTPUT diff --git a/crontab.scm b/crontab.scm index 266311a..d347445 100644 --- a/crontab.scm +++ b/crontab.scm @@ -29,8 +29,8 @@ (define (hit-server user-name) (catch #t (lambda () - (let* ((socket (socket AF_UNIX SOCK_STREAM 0))) - (connect socket AF_UNIX "/var/cron/socket") + (let ((socket (socket AF_UNIX SOCK_STREAM 0))) + (connect socket AF_UNIX config-socket-file) (display user-name socket) (close socket))) (lambda (key . args) @@ -65,8 +65,8 @@ ;; If the real user is not allowed to use crontab due to the /var/cron/allow ;; and/or /var/cron/deny files, bomb out now. -(if (or (eq? (in-access-file? "/var/cron/allow" crontab-real-user) #f) - (eq? (in-access-file? "/var/cron/deny" crontab-real-user) #t)) +(if (or (eq? (in-access-file? config-allow-file crontab-real-user) #f) + (eq? (in-access-file? config-deny-file crontab-real-user) #t)) (begin (display "Access denied by system operator.\n") (primitive-exit 6))) @@ -103,7 +103,7 @@ ;; So now we know which crontab file we will be manipulating. -(define crontab-file (string-append "/var/cron/tabs/" crontab-user)) +(define crontab-file (string-append config-spool-dir "/" crontab-user)) @@ -139,7 +139,9 @@ ;; 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))))) + (let ((temp-file (string-append config-tmp-dir + "/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)) diff --git a/environment.scm b/environment.scm index b340330..82c3a27 100644 --- a/environment.scm +++ b/environment.scm @@ -24,8 +24,8 @@ ;; and represents the cumulated environment settings in a configuration ;; file. When a job definition is seen in a configuration file, the ;; current-environment-mods are copied into the internal job description, and -;; when the job actually runs these environment modifications are applied to the -;; UNIX environment in which the job runs. +;; when the job actually runs these environment modifications are applied to +;; the UNIX environment in which the job runs. @@ -76,8 +76,8 @@ -;; Each time a job is added to the system, we take a snapshot of the current set -;; of environment modifiers. +;; Each time a job is added to the system, we take a snapshot of the current +;; set of environment modifiers. (define (get-current-environment-mods-copy) (list-copy current-environment-mods)) @@ -93,10 +93,11 @@ -;; Procedure to add another environment setting to the alist above. This is used -;; both implicitly by the Vixie parser, and can be used directly by users in -;; scheme configuration files. The return value is purely for the convenience of -;; the parse-vixie-environment in the vixie-specification module (yuk). +;; Procedure to add another environment setting to the alist above. This is +;; used both implicitly by the Vixie parser, and can be used directly by users +;; in scheme configuration files. The return value is purely for the +;; convenience of the parse-vixie-environment in the vixie-specification module +;; (yuk). (define (append-environment-mods name value) (set! current-environment-mods (append current-environment-mods diff --git a/main.scm b/main.scm index 94cb004..0795324 100644 --- a/main.scm +++ b/main.scm @@ -162,8 +162,8 @@ Report bugs to " config-package-bugreport ".\n ;; running. (define (delete-run-file) - (catch #t (lambda () (delete-file "/var/run/cron.pid") - (delete-file "/var/cron/socket")) + (catch #t (lambda () (delete-file config-pid-file) + (delete-file config-socket-file)) noop) (quit)) @@ -187,14 +187,14 @@ Report bugs to " config-package-bugreport ".\n (display "This program must be run by the root user (and should ") (display "have been installed as such).\n") (primitive-exit 16))) - (if (access? "/var/run/cron.pid" F_OK) + (if (access? config-pid-file F_OK) (begin (display "A cron daemon is already running.\n") (display " (If you are sure this is not true, remove the file\n") - (display " /var/run/cron.pid.)\n") + (display " " config-pid-file ".)\n") (primitive-exit 1))) (if (not (option-ref options 'schedule #f)) - (with-output-to-file "/var/run/cron.pid" noop)) + (with-output-to-file config-pid-file noop)) (setenv "MAILTO" #f) (c-set-cron-signals))) @@ -294,12 +294,12 @@ Report bugs to " config-package-bugreport ".\n (define (process-files-in-system-directory) (catch #t (lambda () - (let ((directory (opendir "/var/cron/tabs"))) + (let ((directory (opendir config-spool-dir))) (do ((file-name (readdir directory) (readdir directory))) ((eof-object? file-name)) (and-let* ((user (valid-user file-name))) (set-configuration-user user) - (read-vixie-file (string-append "/var/cron/tabs/" + (read-vixie-file (string-append config-spool-dir file-name)))))) (lambda (key . args) (display "You do not have permission to access the system crontabs.\n") @@ -366,7 +366,7 @@ option.\n") (quit)) (setsid) (if (eq? command-type 'cron) - (with-output-to-file "/var/run/cron.pid" + (with-output-to-file config-pid-file (lambda () (display (getpid)) (newline)))))) @@ -380,7 +380,7 @@ option.\n") (if (eq? command-type 'cron) (let ((socket (socket AF_UNIX SOCK_STREAM 0))) - (bind socket AF_UNIX "/var/cron/socket") + (bind socket AF_UNIX config-socket-file) (listen socket 5) (set! fd-list (list socket)))) @@ -406,7 +406,7 @@ option.\n") (let ((user (getpw user-name))) (remove-user-jobs user) (set-configuration-user user) - (read-vixie-file (string-append "/var/cron/tabs/" user-name)))))) + (read-vixie-file (string-append config-spool-dir "/" user-name)))))) diff --git a/mcron-core.scm b/mcron-core.scm index 90e1da9..0aaacc6 100644 --- a/mcron-core.scm +++ b/mcron-core.scm @@ -40,10 +40,9 @@ ;; ;; (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 +;; where action must be a procedure, and the environment is an alist of ;; modifications that need making to the UNIX environment before the action is -;; run. The next-time elements is the only one that is modified during the +;; run. The next-time element is the only one that is modified during the ;; running of a cron process (i.e. all the others are set once and for all at ;; configuration time). ;; @@ -158,16 +157,16 @@ -;; If the user has requested a schedule of jobs that will run, we provide the -;; information here and then get out. +;; Create a string containing a textual list of the next count jobs to run. ;; -;; Start by determining the number of time points in the future that output is -;; required for. This may be provided on the command line as a parameter to the -;; --schedule option, or else we assume a default of 8. Having determined this -;; count we enter a loop of displaying the next set of jobs to run, artificially +;; Enter a loop of displaying the next set of jobs to run, artificially ;; forwarding the time to the next time point (instead of waiting for it to ;; occur as we would do in a normal run of mcron), and recurse around the loop ;; count times. +;; +;; Note that this has the effect of mutating the job timings. Thus the program +;; must exit after calling this function; the internal data state will be left +;; unusable. (define (get-schedule count) (with-output-to-string @@ -219,6 +218,12 @@ ;; ones to run (may be more than one). Set an alarm and go to sleep. When we ;; wake, run the jobs and reap any children (old jobs) that have ;; completed. Repeat ad infinitum. +;; +;; Note that, if we wake ahead of time, it can only mean that a signal has been +;; sent by a crontab job to tell us to re-read a crontab file. In this case we +;; break out of the loop here, and let the main procedure deal with the +;; situation (it will eventually re-call this function, thus maintaining the +;; loop). (define (run-job-loop . fd-list) diff --git a/mcron.texinfo b/mcron.texinfo.in similarity index 98% rename from mcron.texinfo rename to mcron.texinfo.in index 1eef0e7..41c4b73 100644 --- a/mcron.texinfo +++ b/mcron.texinfo.in @@ -172,13 +172,13 @@ concerns that surround all existing cron programs. The user can obtain an advance schedule of all the jobs that are due to run. @item -Vixie cron is implemented in 4500 lines of C code; mcron is 1500 lines +Vixie cron is implemented in 4500 lines of C code; mcron is 2000 lines of scheme, despite the fact that it offers many more features and much more flexibility, and complete compatibility with Vixie cron. @end itemize A full discussion of the design and philosophy of mcron can be found -in the white paper at http://.../mcron.html [FIXME]. +in the white paper at http://rdmp.org:20202/mcron.html. @node Simple examples, Syntax, Introduction, Top @@ -899,14 +899,14 @@ standard output. @cindex running cron @cindex crond, invokation @cindex running crond -@cindex /var/cron/tabs -@cindex /var/run/cron.pid +@cindex @CONFIG_SPOOL_DIR@ +@cindex @CONFIG_SOCKET_FILE@ 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 +it will read all the files in @code{@CONFIG_SPOOL_DIR@} (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 +@code{@CONFIG_SOCKET_FILE@}, 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. @@ -1047,7 +1047,7 @@ No problems. @item 1 An attempt has been made to start cron but there is already a -/var/run/cron.pid file. If there really is no other cron daemon +@CONFIG_PID_FILE@ file. If there really is no other cron daemon running (this does not include invokations of mcron) then you should remove this file before attempting to run cron. @@ -1065,7 +1065,7 @@ to be specified in one of these forms. @item 4 An attempt to run cron has been made by a user who does not have -permission to access the crontabs in /var/cron/tabs. These files +permission to access the crontabs in @CONFIG_SPOOL_DIR@. These files should be readable only by root, and the cron daemon must be run as root. @@ -1075,7 +1075,7 @@ schedule! @item 6 The system administrator has blocked this user from using crontab with -the files /var/cron/allow and /var/cron/deny. +the files @CONFIG_ALLOW_FILE@ and @CONFIG_DENY_FILE@. @item 7 Crontab has been run with more than one of the arguments @code{-l}, @@ -1102,10 +1102,10 @@ The last component of the name of the program was not one of Either the ~/.cron directory does not exist, or there is a problem reading the files there. -@item 14 -There is a problem writing to /var/cron/update. This is probably -because the crontab program is not installed SUID root, as it should -be. +@c @item 14 +@c There is a problem writing to /var/cron/update. This is probably +@c because the crontab program is not installed SUID root, as it should +@c be. @item 15 Crontab has been run without any arguments at all. There is no default diff --git a/vixie-specification.scm b/vixie-specification.scm index 89c89f4..4af327f 100644 --- a/vixie-specification.scm +++ b/vixie-specification.scm @@ -186,6 +186,6 @@ (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") + (connect socket AF_UNIX config-socket-file) (display "/etc/crontab" socket) (close socket))))))) From 51676b70a8d4e2a13853fd15d81b9e0868171e82 Mon Sep 17 00:00:00 2001 From: dale_mellor Date: Sat, 15 May 2004 12:53:42 +0000 Subject: [PATCH 007/239] Updated all user information to reflect the fact that the project is now properly homed at gnu.org. --- BUGS | 2 ++ ChangeLog | 8 ++++++++ NEWS | 8 +++++++- README | 19 +++++++++---------- configure.ac | 2 +- mcron.texinfo.in | 6 +++--- 6 files changed, 30 insertions(+), 15 deletions(-) diff --git a/BUGS b/BUGS index f48d605..b88c00a 100644 --- a/BUGS +++ b/BUGS @@ -1,6 +1,8 @@ Copyright (C) 2003 Dale Mellor -*-text-*- See the end for copying conditions. +Please send bug reports to bug-mcron@gnu.org. + The currently-known bugs are:- diff --git a/ChangeLog b/ChangeLog index d501f35..4a440d9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2004-05-15 Dale Mellor + + * Modified all auxiliary files to reflect that the package is now + properly homed at www.gnu.org. + + * Bumped version to 1.0.1. + + 2003-12-11 Dale Mellor * Modified all auxiliary files to reflect that we are now a GNU diff --git a/NEWS b/NEWS index 8ee2233..aec756d 100644 --- a/NEWS +++ b/NEWS @@ -3,7 +3,13 @@ Historic moments in the life of mcron. -*-text-*- Copyright (C) 2003 Dale Mellor See the end for copying conditions. -Please send bug reports to bugs-mcron@gnu.org. +Please send bug reports to bug-mcron@gnu.org. + + +Saturday, 15th May 2004 + Set up Savannah and the mailing lists so that we are now homed properly at + gnu.org. Released version 1.0.1 to reflect this, with CVS tag release_1-0-1 + (no branch). Hopefully we will now get some feedback! Friday, 12th December 2003 diff --git a/README b/README index d2ee900..a42cfeb 100644 --- a/README +++ b/README @@ -2,12 +2,12 @@ Copyright (C) 2003 Dale Mellor -*-text-*- See the end for copying conditions. -This is version 1.0.0 of the mcron program, and is the first release as part of -the GNU system. It is designed and written by Dale Mellor, and 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...). +This is version 1.0.1 of the mcron program, and is the first release as part of +the GNU system which is actually homed at gnu.org. It is designed and written by +Dale Mellor, and 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...). ---------------------------------------------------------------------- @@ -57,16 +57,15 @@ are included here. 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 to bugs-mcron@gnu.org. Other mailing lists you +Please send all other bug reports to bug-mcron@gnu.org. Other mailing lists you could subscribe to are help-mcron@gnu.org (for help and advice from the community, including the author) and info-mcron@gnu.org (for news as it happens). Mcron is free software. See the file COPYING for copying conditions. -The mcron development home page is at http://www.gnu.org/software/mcron (also -temporarily at http://rdmp.org/mcron), and can be obtained from -ftp://ftp.gnu.org/mcron (or temporarily from ftp://rdmp.org/mcron). +The mcron development home page is at http://www.gnu.org/software/mcron, and it +can be obtained from ftp://ftp.gnu.org/pub/gnu/mcron. diff --git a/configure.ac b/configure.ac index 6807c39..b58aec0 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, 1.0.0, dale_mellor@users.sourceforge.net) +AC_INIT(mcron, 1.0.1, dale_mellor@users.sourceforge.net) AM_INIT_AUTOMAKE diff --git a/mcron.texinfo.in b/mcron.texinfo.in index 41c4b73..75abfe9 100644 --- a/mcron.texinfo.in +++ b/mcron.texinfo.in @@ -1,13 +1,13 @@ \input texinfo @c %**start of header @setfilename mcron.info -@settitle mcron 1.0.0 +@settitle mcron 1.0.1 @c %**end of header @syncodeindex fn cp @copying -Copyright (C) 2003 Dale Mellor +Copyright (C) 2003 Dale Mellor This is free software. See the source files for the terms of the copyright. @@ -178,7 +178,7 @@ more flexibility, and complete compatibility with Vixie cron. @end itemize A full discussion of the design and philosophy of mcron can be found -in the white paper at http://rdmp.org:20202/mcron.html. +in the white paper at http://www.gnu.org/software/mcron/design.html. @node Simple examples, Syntax, Introduction, Top From 863b755293610f84bc0f871264195076f99a9392 Mon Sep 17 00:00:00 2001 From: dale_mellor Date: Sat, 15 May 2004 13:57:37 +0000 Subject: [PATCH 008/239] Updated for newer autoconf. --- configure.ac | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/configure.ac b/configure.ac index b58aec0..8dbe8dc 100644 --- a/configure.ac +++ b/configure.ac @@ -1,15 +1,14 @@ # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. -AC_PREREQ(2.57) -AC_INIT(mcron, 1.0.1, dale_mellor@users.sourceforge.net) +AC_PREREQ(2.59) +AC_INIT([mcron],[1.0.2],[dale_mellor@users.sourceforge.net]) AM_INIT_AUTOMAKE AC_MSG_CHECKING([whether debugging is requested]) AC_ARG_ENABLE(debug, - AC_HELP_STRING([--enable-debug], - [enable debugging and traceback on error]), + AS_HELP_STRING(--enable-debug,enable debugging and traceback on error), CONFIG_DEBUG=$enableval, CONFIG_DEBUG=no) AC_MSG_RESULT($CONFIG_DEBUG) @@ -90,8 +89,7 @@ SENDMAIL=$ac_cv_prog_SENDMAIL AC_MSG_CHECKING([which spool directory to use]) AC_ARG_WITH(spool-dir, - AC_HELP_STRING([--with-spool-dir], - [the crontab spool directory (/var/cron/tabs)]), + AS_HELP_STRING(--with-spool-dir,the crontab spool directory (/var/cron/tabs)), CONFIG_SPOOL_DIR=$withval, CONFIG_SPOOL_DIR=[/var/cron/tabs]) AC_MSG_RESULT($CONFIG_SPOOL_DIR) @@ -99,8 +97,7 @@ AC_SUBST(CONFIG_SPOOL_DIR) AC_MSG_CHECKING([name of socket]) AC_ARG_WITH(socket-file, - AC_HELP_STRING([--with-socket-file], - [unix pathname for cron socket (/var/cron/socket)]), + AS_HELP_STRING(--with-socket-file,unix pathname for cron socket (/var/cron/socket)), CONFIG_SOCKET_FILE=$withval, CONFIG_SOCKET_FILE=[/var/cron/socket]) AC_MSG_RESULT($CONFIG_SOCKET_FILE) @@ -108,8 +105,7 @@ AC_SUBST(CONFIG_SOCKET_FILE) AC_MSG_CHECKING([name of allow file]) AC_ARG_WITH(allow-file, - AC_HELP_STRING([--with-allow-file], - [the file of allowed users (/var/cron/allow)]), + AS_HELP_STRING(--with-allow-file,the file of allowed users (/var/cron/allow)), CONFIG_ALLOW_FILE=$withval, CONFIG_ALLOW_FILE=[/var/cron/allow]) AC_MSG_RESULT($CONFIG_ALLOW_FILE) @@ -117,8 +113,7 @@ AC_SUBST(CONFIG_ALLOW_FILE) AC_MSG_CHECKING([name of deny file]) AC_ARG_WITH(deny-file, - AC_HELP_STRING([--with-deny-file], - [the file of barred users (/var/cron/deny)]), + AS_HELP_STRING(--with-deny-file,the file of barred users (/var/cron/deny)), CONFIG_DENY_FILE=$withval, CONFIG_DENY_FILE=[/var/cron/deny]) AC_MSG_RESULT($CONFIG_DENY_FILE) @@ -126,8 +121,7 @@ AC_SUBST(CONFIG_DENY_FILE) AC_MSG_CHECKING([name of PID file]) AC_ARG_WITH(pid-file, - AC_HELP_STRING([--with-pid-file], - [the file to record cron's PID (/var/run/cron.pid)]), + AS_HELP_STRING(--with-pid-file,the file to record cron's PID (/var/run/cron.pid)), CONFIG_PID_FILE=$withval, CONFIG_PID_FILE=[/var/run/cron.pid]) AC_MSG_RESULT($CONFIG_PID_FILE) @@ -135,8 +129,7 @@ AC_SUBST(CONFIG_PID_FILE) AC_MSG_CHECKING([directory to hold temporary files]) AC_ARG_WITH(tmp-dir, - AC_HELP_STRING([--with-tmp-dir], - [directory to hold temporary files (/tmp)]), + AS_HELP_STRING(--with-tmp-dir,directory to hold temporary files (/tmp)), CONFIG_TMP_DIR=$withval, CONFIG_TMP_DIR=[/tmp]) AC_MSG_RESULT($CONFIG_TMP_DIR) From b1e921ffc81d460ef0ed7ab6163eb38b654ddf3b Mon Sep 17 00:00:00 2001 From: dale_mellor Date: Sun, 23 Oct 2005 12:29:19 +0000 Subject: [PATCH 009/239] Changes requested by David D. Smith. Non-root install. --- ChangeLog | 17 ++++++++++++++ configure.ac | 44 ++++++++++++++++++++++++++++-------- crontab.scm | 2 ++ job-specifier.scm | 3 +-- main.scm | 3 ++- makefile.am | 50 ++++++++++++++++++++++++----------------- mcron-core.scm | 44 ++++++++++++++++++------------------ mcron.c.template | 49 +++++++++++++++++++++++----------------- mcron.texinfo.in | 29 +++++++++++++++++++----- vixie-specification.scm | 1 + 10 files changed, 161 insertions(+), 81 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4a440d9..9f57f57 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2005-09-02 hydro23 > + + * makefile.am, mcron.c.template (main): Modified install-exec-hook + so that a proper installation of a Vixie-compatible cron only + takes place if we are root - otherwise only mcron is installed as + a user-owned program. The guile modules are now installed under + mcron's shared data directory, not guile's global directories. + + * mcron-core.scm: Removed job:advance-time, put the code inline + where it was called, and changed the instance in the main loop to + compute the new time based on the current-time, rather than the + previous job time (this makes things behave more reasonably when a + laptop awakes from suspend mode). + + * Bumped version to 1.0.2. + + 2004-05-15 Dale Mellor * Modified all auxiliary files to reflect that the package is now diff --git a/configure.ac b/configure.ac index 8dbe8dc..0a1d511 100644 --- a/configure.ac +++ b/configure.ac @@ -1,14 +1,34 @@ # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. + +# Copyright (C) 2003, 2005 Dale Mellor +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + + AC_PREREQ(2.59) -AC_INIT([mcron],[1.0.2],[dale_mellor@users.sourceforge.net]) +AC_INIT([mcron], [1.0.2rc1], [dale_mellor@users.sourceforge.net]) AM_INIT_AUTOMAKE AC_MSG_CHECKING([whether debugging is requested]) AC_ARG_ENABLE(debug, - AS_HELP_STRING(--enable-debug,enable debugging and traceback on error), + AC_HELP_STRING([--enable-debug], + [enable debugging and traceback on error]), CONFIG_DEBUG=$enableval, CONFIG_DEBUG=no) AC_MSG_RESULT($CONFIG_DEBUG) @@ -76,7 +96,7 @@ else AC_CHECK_PROGS(SENDMAIL, mail) if test "x$ac_cv_prog_SENDMAIL" != "x"; then AC_MSG_CHECKING(mail path) - ac_cv_prog_SENDMAIL="`$ac_cv_prog_WHICH sendmail` -d " + ac_cv_prog_SENDMAIL="`$ac_cv_prog_WHICH mail` -d " AC_MSG_RESULT($ac_cv_prog_SENDMAIL) else AC_MSG_RESULT(No mail program found) @@ -89,7 +109,8 @@ SENDMAIL=$ac_cv_prog_SENDMAIL AC_MSG_CHECKING([which spool directory to use]) AC_ARG_WITH(spool-dir, - AS_HELP_STRING(--with-spool-dir,the crontab spool directory (/var/cron/tabs)), + AC_HELP_STRING([--with-spool-dir], + [the crontab spool directory (/var/cron/tabs)]), CONFIG_SPOOL_DIR=$withval, CONFIG_SPOOL_DIR=[/var/cron/tabs]) AC_MSG_RESULT($CONFIG_SPOOL_DIR) @@ -97,7 +118,8 @@ AC_SUBST(CONFIG_SPOOL_DIR) AC_MSG_CHECKING([name of socket]) AC_ARG_WITH(socket-file, - AS_HELP_STRING(--with-socket-file,unix pathname for cron socket (/var/cron/socket)), + AC_HELP_STRING([--with-socket-file], + [unix pathname for cron socket (/var/cron/socket)]), CONFIG_SOCKET_FILE=$withval, CONFIG_SOCKET_FILE=[/var/cron/socket]) AC_MSG_RESULT($CONFIG_SOCKET_FILE) @@ -105,7 +127,8 @@ AC_SUBST(CONFIG_SOCKET_FILE) AC_MSG_CHECKING([name of allow file]) AC_ARG_WITH(allow-file, - AS_HELP_STRING(--with-allow-file,the file of allowed users (/var/cron/allow)), + AC_HELP_STRING([--with-allow-file], + [the file of allowed users (/var/cron/allow)]), CONFIG_ALLOW_FILE=$withval, CONFIG_ALLOW_FILE=[/var/cron/allow]) AC_MSG_RESULT($CONFIG_ALLOW_FILE) @@ -113,7 +136,8 @@ AC_SUBST(CONFIG_ALLOW_FILE) AC_MSG_CHECKING([name of deny file]) AC_ARG_WITH(deny-file, - AS_HELP_STRING(--with-deny-file,the file of barred users (/var/cron/deny)), + AC_HELP_STRING([--with-deny-file], + [the file of barred users (/var/cron/deny)]), CONFIG_DENY_FILE=$withval, CONFIG_DENY_FILE=[/var/cron/deny]) AC_MSG_RESULT($CONFIG_DENY_FILE) @@ -121,7 +145,8 @@ AC_SUBST(CONFIG_DENY_FILE) AC_MSG_CHECKING([name of PID file]) AC_ARG_WITH(pid-file, - AS_HELP_STRING(--with-pid-file,the file to record cron's PID (/var/run/cron.pid)), + AC_HELP_STRING([--with-pid-file], + [the file to record cron's PID (/var/run/cron.pid)]), CONFIG_PID_FILE=$withval, CONFIG_PID_FILE=[/var/run/cron.pid]) AC_MSG_RESULT($CONFIG_PID_FILE) @@ -129,7 +154,8 @@ AC_SUBST(CONFIG_PID_FILE) AC_MSG_CHECKING([directory to hold temporary files]) AC_ARG_WITH(tmp-dir, - AS_HELP_STRING(--with-tmp-dir,directory to hold temporary files (/tmp)), + AC_HELP_STRING([--with-tmp-dir], + [directory to hold temporary files (/tmp)]), CONFIG_TMP_DIR=$withval, CONFIG_TMP_DIR=[/tmp]) AC_MSG_RESULT($CONFIG_TMP_DIR) diff --git a/crontab.scm b/crontab.scm index d347445..e5dfa29 100644 --- a/crontab.scm +++ b/crontab.scm @@ -163,6 +163,8 @@ noop)) + ;; !!!! This comment is wrong. + ;; In the case of the replace personality we loop over all the arguments on the ;; command line, and for each one parse the file to make sure it is parseable ;; (but subsequently ignore the configuration), and all being well we copy it diff --git a/job-specifier.scm b/job-specifier.scm index 3bba9b3..fd4d11b 100644 --- a/job-specifier.scm +++ b/job-specifier.scm @@ -243,7 +243,6 @@ ((list? time-proc) (lambda (current-time) (primitive-eval time-proc))) (else - (display "job: invalid first argument (next-time-function; should ") (display "be function, string or list)") (primitive-exit 3)))) @@ -254,7 +253,7 @@ ((list? action) (with-output-to-string (lambda () (display action))))))) (add-job (lambda (current-time) - (set! current-action-time current-time) + (set! current-action-time current-time) ;; ?? !!!! (time-proc current-time)) action displayable diff --git a/main.scm b/main.scm index 0795324..82b6464 100644 --- a/main.scm +++ b/main.scm @@ -298,8 +298,9 @@ Report bugs to " config-package-bugreport ".\n (do ((file-name (readdir directory) (readdir directory))) ((eof-object? file-name)) (and-let* ((user (valid-user file-name))) - (set-configuration-user user) + (set-configuration-user user) ;; / ?? !!!! (read-vixie-file (string-append config-spool-dir + "/" file-name)))))) (lambda (key . args) (display "You do not have permission to access the system crontabs.\n") diff --git a/makefile.am b/makefile.am index e5efea0..1bc2d94 100644 --- a/makefile.am +++ b/makefile.am @@ -17,7 +17,7 @@ ## Process this file with automake to produce Makefile.in -ED = @ED@ +ED = @ED@ # !!!! Are these needed? CP = @CP@ MAINTAINERCLEANFILES = configure makefile makefile.in \ @@ -28,17 +28,16 @@ CLEANFILES = mcron.c core.scm EXTRA_DIST = makefile.ed main.scm mcron-core.scm vixie-specification.scm \ crontab.scm environment.scm job-specifier.scm redirect.scm \ - vixie-time.scm mcron.c.template + vixie-time.scm mcron.c.template BUGS info_TEXINFOS = mcron.texinfo bin_PROGRAMS = mcron mcron_SOURCES = mcron.c mcron_LDFLAGS = @GUILE_LDFLAGS@ -mcron_CFLAGS = @GUILE_CFLAGS@ +mcron_CFLAGS = @GUILE_CFLAGS@ -DGUILE_LOAD_PATH=\"$(datadir)\" -moddir = @GUILE_SITE@/mcron -mod_DATA = core.scm environment.scm job-specifier.scm redirect.scm \ - vixie-time.scm vixie-specification.scm config.scm +pkgdata_DATA = core.scm environment.scm job-specifier.scm redirect.scm \ + vixie-time.scm vixie-specification.scm config.scm # If you're wondering, the configure script keeps deleting all files with a name @@ -53,24 +52,35 @@ mcron.c : main.scm crontab.scm makefile.ed mcron.c.template @$(ED) < makefile.ed > /dev/null 2>&1 @rm -f mcron.escaped.scm > /dev/null 2>&1 -install-exec-local: - @if [ `id -u` -ne 0 ]; then \ - echo "*** MUST BE ROOT TO INSTALL MCRON ***"; \ - exit 1; \ - fi + +# !!!! Want to be able to install as non-root. + +# install-exec-local: +# @if [ `id -u` -ne 0 ]; then \ +# echo "*** MUST BE ROOT TO INSTALL MCRON ***"; \ +# exit 1; \ +# fi #full program prefix fpp = $(DESTDIR)$(bindir)/@real_program_prefix@ install-exec-hook: - 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 - ./mkinstalldirs -m 'u=rwx,og=rx' @GUILE_SITE@ - ./mkinstalldirs -m 'u=rwx,og=rx' @GUILE_SITE@/mcron + @if [ "`id -u`" -eq "0" ]; then \ + 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; \ + ./mkinstalldirs -m 'u=rwx,og=rx' @GUILE_SITE@; \ + ./mkinstalldirs -m 'u=rwx,og=rx' @GUILE_SITE@/mcron; \ + else \ + echo "+++ WARNING: NON-ROOT INSTALL: ONLY mcron WILL BE INSTALLED, NOT ANY OF THE VIXIE REPLACEMENT PROGRAMS"; \ + fi + uninstall-hook: - rm -f $(fpp){cron,crontab}$(EXEEXT) + if [ "`id -u`" -eq "0" ]; then \ + rm -f $(fpp){cron,crontab}$(EXEEXT); \ + fi + diff --git a/mcron-core.scm b/mcron-core.scm index 0aaacc6..631311a 100644 --- a/mcron-core.scm +++ b/mcron-core.scm @@ -70,8 +70,6 @@ (define (job:environment job) (vector-ref job 3)) (define (job:displayable job) (vector-ref job 4)) (define (job:next-time job) (vector-ref job 5)) -(define (job:advance-time! job) - (vector-set! job 5 ((job:next-time-function job) (job:next-time job)))) @@ -99,21 +97,15 @@ (define (add-job time-proc action displayable configuration-time configuration-user) - (if (eq? configuration-source 'user) - (set! user-job-list (cons (vector configuration-user - time-proc - action - (get-current-environment-mods-copy) - displayable - (time-proc configuration-time)) - user-job-list)) - (set! system-job-list (cons (vector configuration-user - time-proc - action - (get-current-environment-mods-copy) - displayable - (time-proc configuration-time)) - system-job-list)))) + (let ((entry (vector configuration-user + time-proc + action + (get-current-environment-mods-copy) + displayable + (time-proc configuration-time)))) + (if (eq? configuration-source 'user) + (set! user-job-list (cons entry user-job-list)) + (set! system-job-list (cons entry system-job-list))))) @@ -176,10 +168,14 @@ (and-let* ((next-jobs (find-next-jobs)) (time (car next-jobs)) (date-string (strftime "%c\n" (localtime time)))) - (for-each (lambda (job) (display date-string) - (display (job:displayable job)) - (newline)(newline) - (job:advance-time! job)) + (for-each (lambda (job) + (display date-string) + (display (job:displayable job)) + (newline)(newline) + (vector-set! job + 5 + ((job:next-time-function job) + (job:next-time job)))) (cdr next-jobs))))))) @@ -202,6 +198,7 @@ (for-each (lambda (job) (if (eqv? (primitive-fork) 0) (begin + (setgid (passwd:gid (job:user job))) (setuid (passwd:uid (job:user job))) (chdir (passwd:dir (job:user job))) (modify-environment (job:environment job) (job:user job)) @@ -209,7 +206,10 @@ (primitive-exit 0)) (begin (set! number-children (+ number-children 1)) - (job:advance-time! job)))) + (vector-set! job + 5 + ((job:next-time-function job) + (current-time)))))) jobs-list)) diff --git a/mcron.c.template b/mcron.c.template index d99e492..4612f67 100644 --- a/mcron.c.template +++ b/mcron.c.template @@ -62,10 +62,11 @@ which are supposed to initiate shutdown of this program. It calls the scheme procedure (see mcron.scm for details) to do all the work, and then exits. */ -void react_to_terminal_signal (int sig) +void +react_to_terminal_signal (int sig) { - scm_eval_string (scm_take0str ("(delete-run-file)") ); - exit (1); + scm_eval_string (scm_take0str ("(delete-run-file)") ); + exit (1); } @@ -73,17 +74,18 @@ void react_to_terminal_signal (int sig) /* This is a function designed to be callable from scheme, and sets up all the signal handlers required by the cron personality. */ -SCM set_cron_signals () +SCM +set_cron_signals () { - static struct sigaction sa; - memset (&sa, 0, sizeof (sa)); - sa.sa_handler = react_to_terminal_signal; - sigaction (SIGTERM, &sa, 0); - sigaction (SIGINT, &sa, 0); - sigaction (SIGQUIT, &sa, 0); - sigaction (SIGHUP, &sa, 0); - - return SCM_BOOL_T; + static struct sigaction sa; + memset (&sa, 0, sizeof (sa)); + sa.sa_handler = react_to_terminal_signal; + sigaction (SIGTERM, &sa, 0); + sigaction (SIGINT, &sa, 0); + sigaction (SIGQUIT, &sa, 0); + sigaction (SIGHUP, &sa, 0); + + return SCM_BOOL_T; } @@ -92,21 +94,26 @@ SCM set_cron_signals () register the function above with the guile system, and then execute the mcron guile program. */ -void inner_main () +void +inner_main () { - scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); + scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); - scm_eval_string (scm_take0str ( - GUILE_PROGRAM_GOES_HERE - ) ); + scm_eval_string (scm_take0str ( + GUILE_PROGRAM_GOES_HERE + ) ); } /* The real main function. Does nothing but start up the guile subsystem. */ -int main (int argc, char **argv) +int +main (int argc, char **argv) { - scm_boot_guile (argc, argv, inner_main, 0); - return 0; + setenv ("GUILE_LOAD_PATH", GUILE_LOAD_PATH, 1); + + scm_boot_guile (argc, argv, inner_main, 0); + + return 0; } diff --git a/mcron.texinfo.in b/mcron.texinfo.in index 75abfe9..f4a5c08 100644 --- a/mcron.texinfo.in +++ b/mcron.texinfo.in @@ -1,13 +1,13 @@ \input texinfo @c %**start of header @setfilename mcron.info -@settitle mcron 1.0.1 +@settitle mcron 1.0.2 @c %**end of header @syncodeindex fn cp @copying -Copyright (C) 2003 Dale Mellor +Copyright (C) 2003, 2005 Dale Mellor This is free software. See the source files for the terms of the copyright. @@ -107,7 +107,8 @@ Detailed invoking * Running mcron:: * Running cron or crond:: -* Running crontab:: +* Running crontab:: +* Behaviour on laptops:: * Exit codes:: Guile modules @@ -809,7 +810,8 @@ place in the part which implements the mcron personality. @menu * Running mcron:: * Running cron or crond:: -* Running crontab:: +* Running crontab:: +* Behaviour on laptops:: * Exit codes:: @end menu @@ -965,7 +967,7 @@ recommended that this option be used (and further that the @end table -@node Running crontab, Exit codes, Running cron or crond, Invoking +@node Running crontab, Behaviour on laptops, Running cron or crond, Invoking @section Running crontab @cindex crontab, invoking @cindex running crontab @@ -1032,8 +1034,23 @@ become immediately effective. @end table +@node Behaviour on laptops, Exit codes, Running crontab, Invoking +@section Behaviour on laptops +@cindex laptops +@cindex power suspend +While mcron has not been designed to work anachronistically, the behaviour of +mcron when a laptop emerges from a suspended state is well defined, and the +following description explains what happens in this situation. -@node Exit codes, , Running crontab, Invoking +When a laptop awakes from a suspended state, all jobs which would have run while +the laptop was suspended will run exactly once immediately (and simultaneously) +when the laptop awakes, and then the next time that those jobs run will be +computed based on the time the laptop was awoken. Any jobs which would not have +run during the suspense period will be unaffected, and will still run at their +proper times. + + +@node Exit codes, , Behaviour on laptops, Invoking @section Exit codes @cindex exit codes @cindex error conditions diff --git a/vixie-specification.scm b/vixie-specification.scm index 4af327f..08a8699 100644 --- a/vixie-specification.scm +++ b/vixie-specification.scm @@ -29,6 +29,7 @@ read-vixie-port read-vixie-file check-system-crontab) + #:use-module ((mcron config) :select (config-socket-file)) #:use-module (mcron core) #:use-module (mcron job-specifier) #:use-module (mcron redirect) From bbbc3f17a755cbc3c868ea0d5b26b892779de646 Mon Sep 17 00:00:00 2001 From: dale_mellor Date: Mon, 2 Jan 2006 15:07:45 +0000 Subject: [PATCH 010/239] Updated the version to 1.0.2. Made minor edits to the manual, especially with regard to the more esoteric examples. --- configure.ac | 2 +- mcron.texinfo.in | 244 +++++++++++++++++++++++++---------------------- 2 files changed, 129 insertions(+), 117 deletions(-) diff --git a/configure.ac b/configure.ac index 0a1d511..30f8a9f 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ AC_PREREQ(2.59) -AC_INIT([mcron], [1.0.2rc1], [dale_mellor@users.sourceforge.net]) +AC_INIT([mcron], [1.0.2], [dale_mellor@users.sourceforge.net]) AM_INIT_AUTOMAKE diff --git a/mcron.texinfo.in b/mcron.texinfo.in index f4a5c08..ce4c11a 100644 --- a/mcron.texinfo.in +++ b/mcron.texinfo.in @@ -8,7 +8,7 @@ @copying Copyright (C) 2003, 2005 Dale Mellor -This is free software. See the source files for the terms of the +This is free software. See the source files for the terms of the copyright. @ignore @@ -128,45 +128,45 @@ Guile modules @cindex mcron The mcron program represents a complete re-think of the cron concept originally found in the Berkeley and AT&T unices, and subsequently -rationalized by Paul Vixie. The original idea was to have a daemon +rationalized by Paul Vixie. The original idea was to have a daemon that wakes up every minute, scans a set of files under a special directory, and determines from those files if any shell commands should be executed in this minute. The new idea is to read the required command instructions, work out which command needs to be executed next, and then sleep until the -inferred time has arrived. On waking the commands are run, and the -time of the next command is computed. Furthermore, the specifications +inferred time has arrived. On waking the commands are run, and the +time of the next command is computed. Furthermore, the specifications are written in scheme, allowing at the same time simple command execution instructions and very much more flexible ones to be composed -than the original Vixie format. This has several useful advantages +than the original Vixie format. This has several useful advantages over the original idea. @cindex advantages of mcron @itemize @bullet @item -Does not consume CPU resources when not needed. Many cron daemons only +Does not consume CPU resources when not needed. Many cron daemons only run jobs once an hour, or even just once a day. @item Can easily allow for finer time-points to be specified, -i.e. seconds. In principle this could be extended to microseconds, but +i.e. seconds. In principle this could be extended to microseconds, but this is not implemented. @item -Times can be more or less regular. For example, a job that runs +Times can be more or less regular. For example, a job that runs every 17 hours can be specified, or a job that runs on the first Sunday of every month. @item -Times can be dynamic. Arbitrary Guile (scheme) code can be provided to -compute the next time that a command needs to be run. This could, for +Times can be dynamic. Arbitrary Guile (scheme) code can be provided to +compute the next time that a command needs to be run. This could, for example, take the system load into consideration. @item Turns out to be easy to provide complete backwards compatibility with Vixie cron. @item -Each user looks after his own files in his own directory. He can use +Each user looks after his own files in his own directory. He can use more than one to break up complicated cron specifications. @item -Each user can run his own daemon. This removes the need for suid +Each user can run his own daemon. This removes the need for suid programs to manipulate the crontabs, and eliminates many security concerns that surround all existing cron programs. @item @@ -185,8 +185,8 @@ in the white paper at http://www.gnu.org/software/mcron/design.html. @node Simple examples, Syntax, Introduction, Top @chapter Simple examples The vast majority of uses of cron are sublimely simple: run a program -every hour, or every day. With this in mind the design of mcron has -been to allow such simple specifications to be made easily. The +every hour, or every day. With this in mind the design of mcron has +been to allow such simple specifications to be made easily. The examples show how to create the command descriptions, and subsequently how to run mcron to make them happen. @menu @@ -200,7 +200,7 @@ how to run mcron to make them happen. @cindex examples, guile @cindex example, run a program every hour You have an executable @code{my-program} in your home directory, which -you want to run every hour. Create a file @code{job.guile} in directory +you want to run every hour. Create a file @code{job.guile} in directory @code{~/.cron} with the following contents @example @@ -233,7 +233,7 @@ and run the @code{mcron} command. If you want to run other jobs, you can either add more lines to this file, or you can create other files in your @code{.cron} directory -with the @code{.guile} extension. Alternatively, you can use any file +with the @code{.guile} extension. Alternatively, you can use any file you want and pass it as an argument to @code{mcron}, or even pipe the commands into the standard input. @@ -244,7 +244,7 @@ commands into the standard input. @cindex examples, vixie @cindex vixie examples You have an executable @code{my-program} in your home directory, which -you want to run every hour. Create a file @code{job.vixie} in directory +you want to run every hour. Create a file @code{job.vixie} in directory @code{~/.cron} with the following contents @example @@ -258,7 +258,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{cron} 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 @@ -275,26 +275,26 @@ on your system, by root. @cindex syntax, guile @findex job In Guile-formatted configuration files each command that needs -executing is introduced with the @code{job} function. This function +executing is introduced with the @code{job} function. This function always takes two arguments, the first a time specification, and the -second a command specification. An optional third argument may contain +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 -The first argument can be a procedure, a list, or a string. If a +The first argument can be a procedure, a list, or a string. If a function is supplied, it must take exactly one argument, which will be the ``current'' time in UNIX format, and the return value of the function must be the time in UNIX format when this action should next -be run. The following functions are available to facilitate the +be run. The following functions are available to facilitate the computation: @findex next-second-from @code{(next-second-from time . args)} without arguments this -returns the second after the current one. With the extra arguments, +returns the second after the current one. With the extra arguments, these form a list of seconds in the minute when the action should run, and the function will return the time of the next allowed second -(which may be in the next minute of the hour). @footnote{Note that +(which may be in the next minute of the hour). @footnote{Note that while commands can be scheduled to run at any second, it is unlikely that they will be executed then but some time shortly thereafter, depending on the load on the system and the number of jobs that mcron @@ -313,7 +313,7 @@ Similarly to @code{next-second-from}, there are also @findex range Furthermore, the optional argument can be fulfilled by the function @code{(range start end . step)}, which will provide a list of values -from start to (but not including) end, with the step if given. For +from start to (but not including) end, with the step if given. For example @code{(range 0 10 2)} will yield the list @code{'(0 2 4 6 8)}. @findex next-second @@ -339,18 +339,18 @@ list is eval'd). @cindex time specification, vixie-style @cindex vixie-style time specification If the first argument to the @code{job} function is a string, it is -expected to be a Vixie cron-style time specification. See the section +expected to be a Vixie cron-style time specification. See the section on Vixie syntax for this. @cindex job execution @cindex command execution @cindex execution The second argument to the @code{(job)} function can be either a -string, a list, or a function. In all cases the command is executed in -the user's home directory, under the user's own UID. If a string is +string, a list, or a function. In all cases the command is executed in +the user's home directory, under the user's own UID. If a string is passed, it is assumed to be shell script and is executed with the -user's default shell. If a list is passed it is assumed to be scheme -code and is eval'd as such. A supplied function should take exactly +user's default shell. If a list is passed it is assumed to be scheme +code and is eval'd as such. A supplied function should take exactly zero arguments, and will be called at the pertinent times. @subsection Sending output as e-mail @@ -360,10 +360,10 @@ zero arguments, and will be called at the pertinent times. @findex with-mail-out When jobs are specified in a vixie-style configuration, the command is broken at a percentage sign, and the stuff that comes after this is -sent into the command's standard input. Furthermore, any output from -the command is mailed to the user. This functionality is provided for +sent into the command's standard input. Furthermore, any output from +the command is mailed to the user. This functionality is provided for compatibility with Vixie cron, but it is also available to scheme -configuration files. The command (with-mail-out action . user) can be +configuration files. The command (with-mail-out action . user) can be used to direct output from the action (which may be a procedure, list, or string) into an e-mail to the user. @@ -376,10 +376,10 @@ the shell command's standard input. @cindex setting environment variables @findex append-environment-mods Also for compatibility with Vixie cron, mcron has the ability to set -environment variables in configuration files. To access this +environment variables in configuration files. To access this functionality from a scheme configuration file, use the command (append-environment-mods name value), where name is the name of an -environment variable, and value is the value put to it. A value of #f +environment variable, and value is the value put to it. A value of #f will remove the variable from the environment. Note that environment modifications are accumulated as the @@ -394,7 +394,7 @@ before the job specification in the configuration file. @cindex extended guile examples While Guile gives you flexibility to do anything, and the power to represent complex requirements succinctly, things are not always as -they seem. The following examples illustrate some pitfalls, and +they seem. The following examples illustrate some pitfalls, and demonstrate how to code around them. @menu @@ -410,23 +410,17 @@ demonstrate how to code around them. @cindex at command The current implementation of mcron does not provide for an at command (a command-line program that allows the user to specify that a job -runs exactly once at a certain time). This can, however, be achieved. +runs exactly once at a certain time). This can, however, be achieved. Suppose the program @code{my-program} needs to be run at midnight -tonight. A Guile script like the following should work. FIXME: TEST -THIS EXAMPLE. +tonight. A Guile script like the following would work (but a printed +schedule, obtained with the @code{--schedule} option, will show +superfluous entries). @example -(define my-program-flag #t) - -(job (lambda (current-time) - (if my-program-flag - (begin - (set! my-program-flag #f) - (next-day-from current-time)) - 99999999)) +(job '(next-day) (lambda () (system "my-program") - (kill (getppid)))) + (kill (getppid) SIGINT))) @end example @node Every second Sunday, Two hours every day, AT commands, Extended Guile examples @@ -434,7 +428,7 @@ THIS EXAMPLE. @cindex examples, every second sunday To run @code{my-program} on the second Sunday of every month, a Guile script like the following should suffice (it is left as an exercise to -the student to understand how this works!). FIXME: TEST THIS EXAMPLE. +the student to understand how this works!). @example (job (lambda (current-time) @@ -442,11 +436,22 @@ the student to understand how this works!). FIXME: TEST THIS EXAMPLE. (first-day (tm:wday (localtime next-month))) (second-sunday (if (eqv? first-day 0) 8 - (- 15 first-day)))) + (- 14 first-day)))) (+ next-month (* 24 60 60 second-sunday)))) "my-program") @end example +@cindex daylight savings time +Note that this example is also instructive in that it demonstrates +mcron's indeterminacy when the clocks are adjusted for summertime; use +the @code{-s 12} option to @code{mcron}, and see the off-by-one hour +error that occurs twice a year. This is a known problem, that +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). + + @node Two hours every day, Missing the first appointment, Every second Sunday, Extended Guile examples @subsection Two hours every day @@ -461,10 +466,10 @@ effect. @end example Rather than running the my-program program at one o'clock and two -o'clock every day, it will only run it at one o'clock. This is because +o'clock every day, it will only run it at one o'clock. This is because each time mcron has to compute the next time to run the command, it first obtains the next day, and then finds the earliest hour in that -day to run at. Thus, after running the command at one o'clock, the +day to run at. Thus, after running the command at one o'clock, the program first skips forwards to the next midnight (missing the two o'clock appointment), and then finds the next one o'clock schedule. @@ -488,7 +493,7 @@ The command @end example will run @code{my-program} every day at four o'clock in the -afternoon. However, if mcron is started with this script at midday, +afternoon. However, if mcron is started with this script at midday, the first time the command will run will be four o'clock tomorrow; today's appointment will be missed (one time only). @@ -520,9 +525,9 @@ second-to-last day of every month. @cindex vixie definition @cindex vixie compatibility @cindex compatibility, vixie -@emph{NOTE} that this section is definitive. If there is a difference in +@emph{NOTE} that this section is definitive. If there is a difference in behaviour between the mcron program and this part of the manual, then -there is a bug in the program. This section is also copied verbatim +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. @@ -530,10 +535,10 @@ 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 +1. It is allowed to specify days of the month in the range 0-31. What 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 +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 @@ -542,17 +547,17 @@ previous month). @cindex thirteenth month of year @cindex 13th month of year -2. Similarly to the above (but different), months of the year can be -specified in the range 0-12. In the case of mcron (don't know what +2. Similarly to the above (but different), months of the year can be +specified in the range 0-12. In the case of mcron (don't know what Vixie cron did) month 12 will cause the program to wait until January of the following year (but don't rely on this). @cindex shell @cindex environment variables, shell @cindex /etc/passwd -3. Somewhere it says that cron sets the SHELL environment variable to +3. Somewhere it says that cron sets the SHELL environment variable to /bin/sh, and elsewhere it implies that the default behaviour is for -the user's default shell to be used to execute commands. Mcron sets +the user's default shell to be used to execute commands. Mcron sets the variable and runs the command in the user's default shell, as advertised by the /etc/passwd file. @@ -624,7 +629,7 @@ trailing blanks. @cindex HOME environment variable @cindex /etc/passwd Several environment variables are set up automatically by the -@code{cron} daemon. SHELL is set to /bin/sh, and LOGNAME and HOME are +@code{cron} daemon. SHELL is set to /bin/sh, and LOGNAME and HOME are set from the /etc/passwd line of the crontab's owner. HOME and SHELL may be overridden by settings in the crontab; LOGNAME may not. @@ -653,7 +658,7 @@ followed by a user name if this is the system crontab file, followed by a command. Commands are executed by @code{cron} when the minute, hour, and month of year fields match the current time, @strong{and} when at least one of the two day fields (day of month, or day of week) -match the current time (see ``Note'' below). @code{cron} examines cron entries once every minute. +match the current time (see ``Note'' below). @code{cron} examines cron entries once every minute. The time and date fields are: @cindex vixie time specification fields @@ -693,7 +698,7 @@ hours'', just use ``*/2''. Names can also be used for the ``month'' and ``day of week'' fields. Use the first three letters of the particular day or month (case doesn't matter). Ranges or -lists of names are not allowed. @footnote{Mcron allows any alphabetic +lists of names are not allowed. @footnote{Mcron allows any alphabetic characters after a name, so full names of days or months are also valid.} @cindex % character on vixie-style commands @@ -785,14 +790,14 @@ either). @cindex crond program @cindex crontab program The program adopts one of three different personalities depending on -the name used to invoke it. In a standard installation, the program is +the name used to invoke it. In a standard installation, the program is installed in the system under the names mcron, cron and crontab (installed SUID). The recommended way to invoke the program is via the mcron personality -described in the next section. The program can also be run as cron by +described in the next section. The program can also be run as cron by root, and by the SUID program crontab by individual users to gain -backwards compatibility with Vixie cron. However, due to the fact that +backwards compatibility with Vixie cron. However, due to the fact that this daemon process is shared by, and under control of, all the users of the system it is possible (though very unlikely) that it may become unusable, hence the recommendation to use the mcron personality. @@ -800,7 +805,7 @@ unusable, hence the recommendation to use the mcron personality. @cindex deprecated, vixie personality Furthermore, the Vixie personality is considered deprecated by this author (it offers not a single advantage over the mcron personality, -and bloats the code by a factor of three). It is unlikely that this +and bloats the code by a factor of three). It is unlikely that this personality will ever actually go away, but the program may in future be split into two distinct parts, and new developments will only take place in the part which implements the mcron personality. @@ -822,17 +827,20 @@ place in the part which implements the mcron personality. @cindex mcron arguments @cindex command line, mcron @cindex mcron command line -Mcron should be run by the user who wants to schedule his jobs. It may -be made a background job using the facilities of the shell. The basic +Mcron should be run by the user who wants to schedule his jobs. It may +be made a background job using the facilities of the shell. The basic command is @code{mcron [OPTION ...] [file ...]} which has the effect of reading all the configuration files specified (subject to the options) and then waiting until it is time to execute -some command. If no files are given on the command line, then mcron -will look in the user's ~/.cron directory. In either case, files which +some command. If no files are given on the command line, then mcron +will look in the user's ~/.cron directory. In either case, files which end in the extension .vixie or .vix will be assumed to contain Vixie-style crontabs, and files ending .guile or .gle will be assumed -to contain scheme code and will be executed as such. +to contain scheme code and will be executed as such; ANY OTHER FILES +WILL BE IGNORED - specify a file name of ``-'' and then pipe the files +into the standard input if you really want to read them, possibly +using the @code{stdin} option to specify the type of file. The program accepts the following options. @@ -845,12 +853,12 @@ The program accepts the following options. @cindex options, -s @cindex -s option @cindex --schedule option -With this option specified no commands are run. Instead, the program +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. +display. The default value is 8. @cindex daemon option @cindex options, daemon @@ -873,7 +881,7 @@ terminal and run as a daemon process. @itemx --stdin=(vixie|guile) This option is used to indicate whether the configuration information being passed on the standard input is in Vixie format or Guile -format. Guile is the default. +format. Guile is the default. @cindex -v option @cindex --version option @@ -903,19 +911,23 @@ standard output. @cindex running crond @cindex @CONFIG_SPOOL_DIR@ @cindex @CONFIG_SOCKET_FILE@ +NOTE THAT THIS SECTION ONLY APPLIES IF THE @code{cron} or +@code{crond}, and @code{crontab} PROGRAMS HAVE BEEN INSTALLED BY THE +SYSTEM ADMINISTRATOR. + If the program runs by the name of @code{cron} or @code{crond}, then it will read all the files in @code{@CONFIG_SPOOL_DIR@} (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 +process. Additionally, it creates a UNIX socket at @code{@CONFIG_SOCKET_FILE@}, 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 +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. +recently. If so, this file will also be re-read. The options which may be used with this program are as follows. @@ -947,12 +959,12 @@ standard output. @cindex options, -s @cindex -s option @cindex --schedule option -With this option specified no commands are run. Instead, the program +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. +display. The default value is 8. @cindex -n option @cindex --noetc option @@ -961,7 +973,7 @@ display. The default value is 8. @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 +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!) @@ -972,9 +984,9 @@ recommended that this option be used (and further that the @cindex crontab, invoking @cindex running crontab This program is run by individual users to inspect or modify their -crontab files. If a change is made to the file, then the root daemon +crontab files. If a change is made to the file, then the root daemon process will be given a kick, and will immediately read the new -configuration. A warning will be issued to standard output if it +configuration. A warning will be issued to standard output if it appears that a cron daemon is not running. The command is used as @@ -986,7 +998,7 @@ or @code{crontab [-u user] ( -l | -e | -r )} Only the root user can use the -u option, to specify the manipulation -of another user's crontab file. In the first instance, the entire +of another user's crontab file. In the first instance, the entire crontab file of the user is replaced with the contents of the specified file, or standard input if the file is ``-''. @@ -1025,7 +1037,7 @@ Delete the user's crontab file, and exit. @item -e @item --edit Using the editor specified in the user's VISUAL or EDITOR environment -variables, allow the user to edit his crontab. Once the user exits the +variables, allow the user to edit his crontab. Once the user exits the editor, the crontab is checked for parseability, and if it is okay then it is installed as the user's new crontab and the daemon is notified that a change has taken place, so that the new file will @@ -1064,25 +1076,25 @@ No problems. @item 1 An attempt has been made to start cron but there is already a -@CONFIG_PID_FILE@ file. If there really is no other cron daemon +@CONFIG_PID_FILE@ file. If there really is no other cron daemon running (this does not include invokations of mcron) then you should remove this file before attempting to run cron. @item 2 In parsing a guile configuration file, a @code{job} command has been seen but the second argument is neither a procedure, list or -string. This argument is the job's action, and needs to be specified +string. This argument is the job's action, and needs to be specified in one of these forms. @item 3 In parsing a guile configuration file, a @code{job} command has been seen but the first argument is neither a procedure, list or -string. This argument is the job's next-time specification, and needs +string. This argument is the job's next-time specification, and needs to be specified in one of these forms. @item 4 An attempt to run cron has been made by a user who does not have -permission to access the crontabs in @CONFIG_SPOOL_DIR@. These files +permission to access the crontabs in @CONFIG_SPOOL_DIR@. These files should be readable only by root, and the cron daemon must be run as root. @@ -1096,11 +1108,11 @@ the files @CONFIG_ALLOW_FILE@ and @CONFIG_DENY_FILE@. @item 7 Crontab has been run with more than one of the arguments @code{-l}, -@code{-r}, @code{-e}. These are mutually exclusive options. +@code{-r}, @code{-e}. These are mutually exclusive options. @item 8 Crontab has been run with the -u option by a user other than -root. Only root is allowed to use this option. +root. Only root is allowed to use this option. @item 9 An invalid vixie-style time specification has been supplied. @@ -1120,12 +1132,12 @@ Either the ~/.cron directory does not exist, or there is a problem reading the files there. @c @item 14 -@c There is a problem writing to /var/cron/update. This is probably +@c There is a problem writing to /var/cron/update. This is probably @c because the crontab program is not installed SUID root, as it should @c be. @item 15 -Crontab has been run without any arguments at all. There is no default +Crontab has been run without any arguments at all. There is no default behaviour in this case. @item 16 @@ -1144,13 +1156,13 @@ programs if they are linked against libguile. It may be, for example, that a program needs to perform house-keeping functions at certain times of the day, in which case it can spawn (either fork or thread) a sub-process which uses a built-in -mcron. Another example may be a program which must sleep until some +mcron. Another example may be a program which must sleep until some non-absolute time specified on the Gregorian calendar (the first day -of next week, for example). Finally, it may be the wish of the user to +of next week, for example). Finally, it may be the wish of the user to provide a program with the functionality of mcron plus a bit extra. The core module maintains mcron's internal job lists, and provides the -main wait-run-wait loop that is mcron's main function. It also +main wait-run-wait loop that is mcron's main function. It also introduces the facilities for accumulating a set of environment modifiers, which take effect when jobs run. @@ -1169,16 +1181,16 @@ modifiers, which take effect when jobs run. @cindex modules, core This module may be used by including @code{(use-modules (mcron core))} -in a program. The main functions are @code{add-job} and +in a program. The main functions are @code{add-job} and @code{run-job-loop}, which allow a program to create a list of job specifications to run, and then to initiate the wait-run-wait loop -firing the jobs off at the requisite times. However, before they are +firing the jobs off at the requisite times. However, before they are introduced two functions which manipulate the environment that takes effect when a job runs are defined. @cindex environment The environment is a set of name-value pairs which is built up -incrementally. Each time the @code{add-job} function is called, the +incrementally. Each time the @code{add-job} function is called, the environment modifiers that have been accumulated up to that point are stored with the new job specification, and when the job actually runs these name-value pairs are used to modify the run-time environment in @@ -1196,16 +1208,16 @@ specified so far to be forgotten. @deffn{Scheme procedure} add-job time-proc action displayable configuration-time configuration-user This procedure adds a job specification to the list of all jobs to -run. @var{time-proc} should be a procedure taking exactly one argument -which will be a UNIX time. This procedure must compute the next time -that the job should run, and return the result. @var{action} should be +run. @var{time-proc} should be a procedure taking exactly one argument +which will be a UNIX time. This procedure must compute the next time +that the job should run, and return the result. @var{action} should be a procedure taking no arguments, and contains the instructions that actually get executed whenever the job is scheduled to -run. @var{displayable} should be a string, and is only for the use of +run. @var{displayable} should be a string, and is only for the use of humans; it can be anything which identifies or simply gives a clue as -to the purpose or function of this job. @var{configuration-time} is +to the purpose or function of this job. @var{configuration-time} is the time from which the first invokation of this job should be -computed. Finally, @var{configuration-user} should be the passwd entry +computed. Finally, @var{configuration-user} should be the passwd entry for the user under whose personality the job is to run. @end deffn @@ -1215,9 +1227,9 @@ for the user under whose personality the job is to run. This procedure returns only under exceptional circumstances, but usually loops forever waiting for the next time to arrive when a job needs to run, running that job, recomputing the next run time, and -then waiting again. However, the wait can be interrupted by data +then waiting again. However, the wait can be interrupted by data becoming available for reading on one of the file descriptors in the -fd-list, if supplied. Only in this case will the procedure return to +fd-list, if supplied. Only in this case will the procedure return to the calling program, which may then make modifications to the job list before calling the @code{run-job-loop} procedure again to resume execution of the mcron core. @@ -1227,17 +1239,17 @@ the mcron core. The argument @var{user} should be a string naming a user (his login name), or an integer UID, or an object representing the user's passwd -entry. All jobs on the current job list that are scheduled to be run +entry. All jobs on the current job list that are scheduled to be run under this personality are removed from the job list. @end deffn @deffn{Scheme procedure} get-schedule count @cindex schedule of jobs The argument @var{count} should be an integer value giving the number -of time-points in the future to report that jobs will run as. Note +of time-points in the future to report that jobs will run as. Note that this procedure is disruptive; if @code{run-job-loop} is called after this procedure, the first job to run will be the one after the -last job that was reported in the schedule report. The report itself +last job that was reported in the schedule report. The report itself is returned to the calling program as a string. @end deffn @@ -1250,7 +1262,7 @@ This module is introduced to a program with the command @code{(use-modules (mcron redirect))}. This module provides the @code{with-mail-out} function, described -fully in @ref{Guile Syntax}. +fully in @ref{Guile Syntax}. @node The vixie-time module, The job-specifier module, The redirect module, Guile modules @section The vixie-time module @@ -1263,7 +1275,7 @@ vixie-time))}. This module provides a single method for converting a vixie-style time specification into a procedure which can be used as the @code{next-time-function} to the core @code{add-job} procedure, or to -the @code{job-specifier} @code{job} procedure. See @ref{Vixie Syntax} +the @code{job-specifier} @code{job} procedure. See @ref{Vixie Syntax} for full details of the allowed format for the time string. @deffn{Scheme procedure} parse-vixie-time time-string @@ -1287,7 +1299,7 @@ configuration files, namely @code{range}, @code{next-year-from}, @code{next-day-from}, @code{next-day}, @code{next-hour-from}, @code{next-hour}, @code{next-minute-from}, @code{next-minute}, @code{next-second-from}, @code{next-second}, - and last but not least, @code{job}. See @ref{Guile Syntax} for full + and last but not least, @code{job}. See @ref{Guile Syntax} for full details. Once this module is loaded, a scheme configuration file can be used to @@ -1320,7 +1332,7 @@ as the optional argument. @deffn{Scheme procedure} read-vixie-file name . parse-line This procedure attempts to open the named file, and if it fails will -return silently. Otherwise, the behaviour is identical to +return silently. Otherwise, the behaviour is identical to @code{read-vixie-port} above. @end deffn From 4c3a7cc36c29ecbb8574454f0f5bdbed7ef66f8b Mon Sep 17 00:00:00 2001 From: dale_mellor Date: Mon, 2 Jan 2006 17:15:32 +0000 Subject: [PATCH 011/239] Noted release of version 1.0.2. --- NEWS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS b/NEWS index aec756d..5a17a53 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,10 @@ See the end for copying conditions. Please send bug reports to bug-mcron@gnu.org. +Monday, 2nd January 2006 + Released version 1.0.2. + + Saturday, 15th May 2004 Set up Savannah and the mailing lists so that we are now homed properly at gnu.org. Released version 1.0.1 to reflect this, with CVS tag release_1-0-1 From 011df9b8fd152554619f76ea1e35a68ef206762d Mon Sep 17 00:00:00 2001 From: dale_mellor Date: Sun, 16 Apr 2006 22:10:43 +0000 Subject: [PATCH 012/239] Update to 1.0.3. Lots of small changes, mainly to work with guile 1.8.0. Daylight savings time is now handled okay. Bug fix in Vixie parser. User gets option to correct bad crontab entries. --- BUGS | 7 +- NEWS | 14 ++- README | 6 +- configure.ac | 8 +- crontab.scm | 73 ++++++++---- job-specifier.scm | 27 +++-- main.scm | 258 ++++++++++++++++++++++++++-------------- makefile.am | 2 +- mcron-core.scm | 59 +++++---- mcron.c.template | 1 + mcron.texinfo.in | 95 +++++++-------- vixie-specification.scm | 75 +++++++----- vixie-time.scm | 132 ++++++++++++-------- 13 files changed, 463 insertions(+), 294 deletions(-) diff --git a/BUGS b/BUGS index b88c00a..a15ecbc 100644 --- a/BUGS +++ b/BUGS @@ -6,12 +6,7 @@ Please send bug reports to bug-mcron@gnu.org. The currently-known bugs are:- -* 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). - - + -NONE- _______________________________________________________________________________ diff --git a/NEWS b/NEWS index 5a17a53..8663d8f 100644 --- a/NEWS +++ b/NEWS @@ -1,11 +1,20 @@ Historic moments in the life of mcron. -*-text-*- -Copyright (C) 2003 Dale Mellor +Copyright (C) 2003, 2006 Dale Mellor See the end for copying conditions. Please send bug reports to bug-mcron@gnu.org. +Sunday, 16th April 2006 + Released version 1.0.3. Incorporated many coding suggestions by Sergey + Poznyakoff, which makes the program work with daylight savings time shifts, + fixes a bug in parsing Vixie-style input files, allows a user the + opportunity to correct a crontab entry instead of just wiping out the file. + Made it work with Guile 1.8. Updated the manual with GFDL and some minor + suggestions from Karl Berry. + + Monday, 2nd January 2006 Released version 1.0.2. @@ -60,9 +69,8 @@ Friday, 4th July 2003 - ____________________________________________________________________________ -Copyright (C) 2003 Dale Mellor +Copyright (C) 2003, 2006 Dale Mellor Permission is granted to anyone to make or distribute verbatim copies of this document as received, in any medium, provided that the diff --git a/README b/README index a42cfeb..41c6092 100644 --- a/README +++ b/README @@ -2,8 +2,7 @@ Copyright (C) 2003 Dale Mellor -*-text-*- See the end for copying conditions. -This is version 1.0.1 of the mcron program, and is the first release as part of -the GNU system which is actually homed at gnu.org. It is designed and written by +This is version 1.0.3 of the GNU mcron program. It is designed and written by Dale Mellor, and 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 @@ -18,7 +17,8 @@ Read the BUGS file. 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. +For use as a replacement cron daemon on a system, 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 diff --git a/configure.ac b/configure.ac index 30f8a9f..cf11ad4 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ AC_PREREQ(2.59) -AC_INIT([mcron], [1.0.2], [dale_mellor@users.sourceforge.net]) +AC_INIT([mcron], [1.0.3], [dale_mellor@users.sourceforge.net]) AM_INIT_AUTOMAKE @@ -74,12 +74,12 @@ fi # Check the Guile version. -AC_MSG_CHECKING(for guile version >= 1.6.4) +AC_MSG_CHECKING(for guile version >= 1.8.0) if [$GUILE --version | $HEAD -1 | $AWK '{print $2}' | \ - $EGREP -q '^(1\.(6\.([4-9]|[1-3][^.])|[7-9]|[1-5][^.])|[2-9])']; then + $EGREP -q '^1\.8\.']; then AC_MSG_RESULT(OK) else - AC_MSG_ERROR([Sorry, Guile 1.6.4 or greater is needed to run mcron]) + AC_MSG_ERROR([Sorry, Guile 1.8.0 or greater is needed to run mcron]) fi diff --git a/crontab.scm b/crontab.scm index e5dfa29..96d8b3c 100644 --- a/crontab.scm +++ b/crontab.scm @@ -67,9 +67,7 @@ (if (or (eq? (in-access-file? config-allow-file crontab-real-user) #f) (eq? (in-access-file? config-deny-file crontab-real-user) #t)) - (begin - (display "Access denied by system operator.\n") - (primitive-exit 6))) + (mcron-error 6 "Access denied by system operator.")) @@ -79,9 +77,7 @@ (if (option-ref options 'list #f) 1 0) (if (option-ref options 'remove #f) 1 0)) 1) - (begin - (display "crontab: Only one of options -e, -l or -r can be used.\n") - (primitive-exit 7))) + (mcron-error 7 "Only one of options -e, -l or -r can be used.")) @@ -89,8 +85,7 @@ (if (and (not (eqv? (getuid) 0)) (option-ref options 'user #f)) - (begin (display "crontab: Only root can use the -u option.\n") - (primitive-exit 8))) + (mcron-error 8 "Only root can use the -u option.")) @@ -107,6 +102,24 @@ +;; Display the prompt and wait for user to type his choice. Return #t if the +;; answer begins with 'y' or 'Y', return #f if it begins with 'n' or 'N', +;; otherwise ask again. + +(define (get-yes-no prompt . re-prompt) + (if (not (null? re-prompt)) + (display "Please answer y or n.\n")) + (display (string-append prompt " ")) + (let ((r (read-line))) + (if (not (string-null? r)) + (case (string-ref r 0) + ((#\y #\Y) #t) + ((#\n #\N) #f) + (else (get-yes-no prompt #t))) + (get-yes-no prompt #t)))) + + + ;; There are four possible sub-personalities to the crontab personality: list, ;; remove, edit and replace (when the user uses no options but supplies file ;; names on the command line). @@ -136,7 +149,9 @@ ;; it; once the editor returns we try to read the file to check that it is ;; parseable (but do nothing more with the configuration), and if it is okay ;; (this program is still running!) we move the temporary file to the real - ;; crontab, wake the cron daemon up, and remove the temporary file. + ;; crontab, wake the cron daemon up, and remove the temporary file. If the + ;; parse fails, we give user a choice of editing the file again or quitting + ;; the program and losing all changes made. ((option-ref options 'edit #f) (let ((temp-file (string-append config-tmp-dir @@ -145,10 +160,20 @@ (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 (or (getenv "VISUAL") (getenv "EDITOR") "vi") - " " - temp-file)) - (read-vixie-file temp-file) + (let retry () + (system (string-append + (or (getenv "VISUAL") (getenv "EDITOR") "vi") + " " + temp-file)) + (catch 'mcron-error + (lambda () (read-vixie-file temp-file)) + (lambda (key exit-code . msg) + (apply mcron-error 0 msg) + (if (get-yes-no "Edit again?") + (retry) + (begin + (mcron-error 0 "Crontab not changed") + (primitive-exit 0)))))) (copy-file temp-file crontab-file) (delete-file temp-file) (hit-server crontab-user))) @@ -174,20 +199,20 @@ ((not (null? (option-ref options '() '()))) (let ((input-file (car (option-ref options '() '())))) - (if (string=? input-file "-") - (let ((input-string (stdin->string))) - (read-vixie-port (open-input-string input-string)) - (with-output-to-file crontab-file (lambda () - (display input-string)))) - (begin - (read-vixie-file input-file) - (copy-file input-file crontab-file)))) - (hit-server crontab-user)) + (catch-mcron-error + (if (string=? input-file "-") + (let ((input-string (stdin->string))) + (read-vixie-port (open-input-string input-string)) + (with-output-to-file crontab-file (lambda () + (display input-string)))) + (begin + (read-vixie-file input-file) + (copy-file input-file crontab-file)))) + (hit-server crontab-user))) ;; The user is being silly. The message here is identical to the one Vixie cron ;; used to put out, for total compatibility. (else - (display "crontab: usage error: file name must be specified for replace.\n") - (primitive-exit 15))) + (mcron-error 15 "usage error: file name must be specified for replace."))) diff --git a/job-specifier.scm b/job-specifier.scm index fd4d11b..52e655f 100644 --- a/job-specifier.scm +++ b/job-specifier.scm @@ -233,9 +233,10 @@ ((list? action) (lambda () (primitive-eval action))) ((string? action) (lambda () (system action))) (else - (display "job: invalid second argument (action; should be lamdba") - (display "function, string or list)\n") - (primitive-exit 2)))) + (throw 'mcron-error + 2 + "job: invalid second argument (action; should be lambda" + " function, string or list)")))) (time-proc (cond ((procedure? time-proc) time-proc) @@ -243,9 +244,10 @@ ((list? time-proc) (lambda (current-time) (primitive-eval time-proc))) (else - (display "job: invalid first argument (next-time-function; should ") - (display "be function, string or list)") - (primitive-exit 3)))) + (throw 'mcron-error + 3 + "job: invalid first argument (next-time-function; should ") + "be function, string or list)"))) (displayable (cond ((not (null? displayable)) (car displayable)) ((procedure? action) "Lambda function") @@ -253,8 +255,17 @@ ((list? action) (with-output-to-string (lambda () (display action))))))) (add-job (lambda (current-time) - (set! current-action-time current-time) ;; ?? !!!! - (time-proc current-time)) + (set! current-action-time current-time) ;; ?? !!!! Code + + ;; Contributed by Sergey Poznyakoff to allow for daylight savings + ;; time changes. + (let* ((next (time-proc current-time)) + (gmtoff (tm:gmtoff (localtime next))) + (d (+ next (- gmtoff + (tm:gmtoff (localtime current-time)))))) + (if (eqv? (tm:gmtoff (localtime d)) gmtoff) + d + next))) action displayable configuration-time diff --git a/main.scm b/main.scm index 82b6464..9017276 100644 --- a/main.scm +++ b/main.scm @@ -43,13 +43,39 @@ ;; backwards for the first non-alphabetic character. This allows names like ;; in.cron to be accepted as an invocation of the cron command. -(use-modules (ice-9 regex)) +(use-modules (ice-9 regex) (ice-9 rdelim)) (define command-name (match:substring (regexp-exec (make-regexp "[[:alpha:]]*$") (car (command-line))))) +;; Code contributed by Sergey Poznyakoff. Print an error message (made up from +;; the parts of rest), and if the error is fatal (present and non-zero) then +;; exit to the system with this code. + +(define (mcron-error exit-code . rest) + (with-output-to-port (current-error-port) + (lambda () + (for-each display (append (list command-name ": ") rest)) + (newline))) + (if (and exit-code (not (eq? exit-code 0))) + (primitive-exit exit-code))) + + + +;; Code contributed by Sergey Poznyakoff. Execute body. If an 'mcron-error +;; exception occurs, print its diagnostics and exit with its error code. + +(defmacro catch-mcron-error (. body) + `(catch 'mcron-error + (lambda () + ,@body) + (lambda (key exit-code . msg) + (apply mcron-error exit-code msg)))) + + + ;; We will be doing a lot of testing of the command name, so it makes sense to ;; perform the string comparisons once and for all here. @@ -58,8 +84,7 @@ (string=? command-name "crond")) 'cron) ((string=? command-name "crontab") 'crontab) (else - (display "The command name is invalid.\n") - (primitive-exit 12)))) + (mcron-error 12 "The command name is invalid.")))) @@ -70,26 +95,34 @@ (use-modules (ice-9 getopt-long)) (define options - (getopt-long (command-line) - (append - (case command-type ('crontab - '((user (single-char #\u) (value #t)) - (edit (single-char #\e) (value #f)) - (list (single-char #\l) (value #f)) - (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) + (catch + 'misc-error + (lambda () + (getopt-long (command-line) + (append + (case command-type + ((crontab) + '((user (single-char #\u) (value #t)) + (edit (single-char #\e) (value #f)) + (list (single-char #\l) (value #f)) + (remove (single-char #\r) (value #f)))) + (else `((schedule (single-char #\s) + (value optional) + (predicate ;; Added by Sergey Poznyakoff. + ,(lambda (value) + (or (eq? value #t) + (string->number value))))) + (daemon (single-char #\d) (value #f)) + (noetc (single-char #\n) (value #f)) + (stdin (single-char #\i) (value #t) + (predicate + ,(lambda (value) (or (string=? "vixie" value) (string=? "guile" value)))))))) - '((version (single-char #\v) (value #f)) - (help (single-char #\h) (value #f)))))) - - - + '((version (single-char #\v) (value #f)) + (help (single-char #\h) (value #f)))))) + (lambda (key func fmt args . rest) + (mcron-error 1 (apply format (append (list #f fmt) args)))))) ;; If the user asked for the version of this program, give it to him and get ;; out. @@ -100,7 +133,7 @@ " command-name " (" config-package-string ")\n Written by Dale Mellor\n \n -Copyright (C) 2003 Dale Mellor\n +Copyright (C) 2003, 2006 Dale Mellor\n This is free software; see the source for copying conditions. There is NO\n warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n ")) @@ -114,7 +147,9 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n (begin (display (string-append " Usage: " (car (command-line)) -(case command-type ('mcron +(case command-type + + ((mcron) " [OPTIONS] [FILES]\n Run an mcron process according to the specifications in the FILES (`-' for\n standard input), or use all the files in ~/.cron with .guile or .vixie\n @@ -126,10 +161,10 @@ extensions.\n will be run by mcron\n -d, --daemon Immediately detach the program from the terminal and\n run as a daemon process\n - -i, --stdin=(guile|vixie) Format of data passed as standard input\n - (default guile)") + -i, --stdin=(guile|vixie) Format of data passed as standard input or\n + file arguments (default guile)") - ('cron + ((cron) " [OPTIONS]\n Unless an option is specified, run a cron daemon as a detached process, \n reading all the information in the users' crontabs and in /etc/crontab.\n @@ -141,13 +176,15 @@ reading all the information in the users' crontabs and in /etc/crontab.\n -n, --noetc Do not check /etc/crontab for updates (HIGHLY\n RECOMMENDED).") - ('crontab + ((crontab) (string-append " [-u user] file\n" " " (car (command-line)) " [-u user] { -e | -l | -r }\n" " (default operation is replace, per 1003.2)\n" " -e (edit user's crontab)\n" " -l (list user's crontab)\n" - " -r (delete user's crontab)\n"))) + " -r (delete user's crontab)\n")) + + (else "rubbish")) "\n\n Report bugs to " config-package-bugreport ".\n @@ -158,7 +195,7 @@ Report bugs to " config-package-bugreport ".\n ;; This is called from the C front-end whenever a terminal signal is ;; received. We remove the /var/run/cron.pid file so that crontab and other -;; invokations of cron don't get the wrong idea that a daemon is currently +;; invocations of cron don't get the wrong idea that a daemon is currently ;; running. (define (delete-run-file) @@ -183,16 +220,16 @@ Report bugs to " config-package-bugreport ".\n (if (eq? command-type 'cron) (begin (if (not (eqv? (getuid) 0)) - (begin - (display "This program must be run by the root user (and should ") - (display "have been installed as such).\n") - (primitive-exit 16))) + (mcron-error 16 + "This program must be run by the root user (and should " + "have been installed as such).")) (if (access? config-pid-file F_OK) - (begin - (display "A cron daemon is already running.\n") - (display " (If you are sure this is not true, remove the file\n") - (display " " config-pid-file ".)\n") - (primitive-exit 1))) + (mcron-error 1 + "A cron daemon is already running.\n" + " (If you are sure this is not true, remove the file\n" + " " + config-pid-file + ".)")) (if (not (option-ref options 'schedule #f)) (with-output-to-file config-pid-file noop)) (setenv "MAILTO" #f) @@ -230,6 +267,19 @@ Report bugs to " config-package-bugreport ".\n +;; Code contributed by Sergey Poznyakoff. Determine if the given file is a +;; regular file or not. + +(define (regular-file? file) + (catch 'system-error + (lambda () + (eq? (stat:type (stat file)) 'regular)) + (lambda (key call fmt args . rest) + (mcron-error 0 (apply format (append (list #f fmt) args))) + #f))) + + + ;; Procedure which processes any configuration file according to the ;; extension. If a file is not recognized, it is silently ignored (this deals ;; properly with most editors' backup files, for instance). @@ -259,12 +309,12 @@ Report bugs to " config-package-bugreport ".\n (directory (opendir dir-path))) (do ((file-name (readdir directory) (readdir directory))) ((eof-object? file-name) (closedir directory)) - (process-user-file (string-append dir-path - "/" - file-name))))) + (process-user-file (string-append dir-path + "/" + file-name))))) (lambda (key . args) - (display "Cannot read files in your ~/.cron directory.\n") - (primitive-exit 13)))) + (mcron-error 13 "Cannot read files in your ~/.cron directory.")))) + @@ -293,18 +343,21 @@ Report bugs to " config-package-bugreport ".\n (use-modules (srfi srfi-2)) ;; For and-let*. (define (process-files-in-system-directory) - (catch #t (lambda () - (let ((directory (opendir config-spool-dir))) - (do ((file-name (readdir directory) (readdir directory))) - ((eof-object? file-name)) - (and-let* ((user (valid-user file-name))) - (set-configuration-user user) ;; / ?? !!!! - (read-vixie-file (string-append config-spool-dir - "/" - file-name)))))) - (lambda (key . args) - (display "You do not have permission to access the system crontabs.\n") - (primitive-exit 4)))) + (catch #t + (lambda () + (let ((directory (opendir config-spool-dir))) + (do ((file-name (readdir directory) (readdir directory))) + ((eof-object? file-name)) + (and-let* ((user (valid-user file-name))) + (set-configuration-user user) ;; / ?? !!!! + (catch-mcron-error + (read-vixie-file (string-append config-spool-dir + "/" + file-name))))))) + (lambda (key . args) + (mcron-error + 4 + "You do not have permission to access the system crontabs.")))) @@ -316,27 +369,28 @@ Report bugs to " config-package-bugreport ".\n ;; /var/cron/tabs directory and also the /etc/crontab file. (case command-type - ('mcron (if (null? (option-ref options '() '())) - (process-files-in-user-directory) - (for-each (lambda (file-path) - (process-user-file file-path)) - (option-ref options '() '())))) - - ('cron (process-files-in-system-directory) - (use-system-job-list) - (read-vixie-file "/etc/crontab" parse-system-vixie-line) - (use-user-job-list) - (if (not (option-ref options 'noetc #f)) - (begin - (display -"WARNING: cron will check for updates to /etc/crontab EVERY MINUTE. If you do\n + ((mcron) (if (null? (option-ref options '() '())) + (process-files-in-user-directory) + (for-each (lambda (file-path) + (process-user-file file-path)) + (option-ref options '() '())))) + + ((cron) (process-files-in-system-directory) + (use-system-job-list) + (catch-mcron-error + (read-vixie-file "/etc/crontab" parse-system-vixie-line)) + (use-user-job-list) + (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 "root") - (job '(- (next-minute-from (next-minute)) 6) - check-system-crontab - "/etc/crontab update checker."))))) + (set-configuration-user "root") + (job '(- (next-minute-from (next-minute)) 6) + check-system-crontab + "/etc/crontab update checker."))))) @@ -380,10 +434,18 @@ option.\n") (define fd-list '()) (if (eq? command-type 'cron) - (let ((socket (socket AF_UNIX SOCK_STREAM 0))) - (bind socket AF_UNIX config-socket-file) - (listen socket 5) - (set! fd-list (list socket)))) + (catch #t + (lambda () + (let ((socket (socket AF_UNIX SOCK_STREAM 0))) + (bind socket AF_UNIX config-socket-file) + (listen socket 5) + (set! fd-list (list socket)))) + (lambda (key . args) + (delete-file config-pid-file) + (mcron-error 1 + "Cannot bind to UNIX socket " + config-socket-file)))) + @@ -398,23 +460,39 @@ option.\n") (user-name (read-line socket))) (close socket) (set-configuration-time (current-time)) - (if (string=? user-name "/etc/crontab") - (begin - (clear-system-jobs) - (use-system-job-list) - (read-vixie-file "/etc/crontab" parse-system-vixie-line) - (use-user-job-list)) - (let ((user (getpw user-name))) - (remove-user-jobs user) - (set-configuration-user user) - (read-vixie-file (string-append config-spool-dir "/" user-name)))))) + (catch-mcron-error + (if (string=? user-name "/etc/crontab") + (begin + (clear-system-jobs) + (use-system-job-list) + (read-vixie-file "/etc/crontab" parse-system-vixie-line) + (use-user-job-list)) + (let ((user (getpw user-name))) + (remove-user-jobs user) + (set-configuration-user user) + (read-vixie-file (string-append config-spool-dir "/" user-name))))))) + + + +;; Added by Sergey Poznyakoff. This no-op will collect zombie child processes +;; as soon as they die. This is a big improvement as previously they stayed +;; around the system until the next time mcron wakes to fire a new job off. + +;; Unfortunately it seems to interact badly with the select system call, +;; wreaking havoc... + +;; (sigaction SIGCHLD (lambda (sig) noop) SA_RESTART) ;; Now the main loop. Forever execute the run-job-loop procedure in the mcron ;; core, and when it drops out (can only be because a message has come in on the ;; socket) we process the socket request before restarting the loop again. +;; Sergey Poznyakoff: we can also drop out of run-job-loop because of a SIGCHLD, +;; so must test fd-list. -(while #t - (run-job-loop fd-list) - (process-update-request)) +(catch-mcron-error + (while #t + (run-job-loop fd-list) + (if (not (null? fd-list)) + (process-update-request)))) diff --git a/makefile.am b/makefile.am index 1bc2d94..b3d32d8 100644 --- a/makefile.am +++ b/makefile.am @@ -20,7 +20,7 @@ ED = @ED@ # !!!! Are these needed? CP = @CP@ -MAINTAINERCLEANFILES = configure makefile makefile.in \ +MAINTAINERCLEANFILES = configure makefile makefile.in config.guess config.sub \ install-sh missing mkinstalldirs texinfo.tex INSTALL \ aclocal.m4 compile depcomp COPYING diff --git a/mcron-core.scm b/mcron-core.scm index 631311a..b8ca289 100644 --- a/mcron-core.scm +++ b/mcron-core.scm @@ -167,7 +167,7 @@ ((eqv? count 0)) (and-let* ((next-jobs (find-next-jobs)) (time (car next-jobs)) - (date-string (strftime "%c\n" (localtime time)))) + (date-string (strftime "%c %z\n" (localtime time)))) (for-each (lambda (job) (display date-string) (display (job:displayable job)) @@ -214,6 +214,16 @@ +;; Give any zombie children a chance to die, and decrease the number known to +;; exist. + +(define (child-cleanup) + (do () ((or (<= number-children 0) + (eqv? (car (waitpid WAIT_ANY WNOHANG)) 0))) + (set! number-children (- number-children 1)))) + + + ;; Now the main loop. 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 and reap any children (old jobs) that have @@ -227,26 +237,35 @@ (define (run-job-loop . fd-list) - (call-with-current-continuation (lambda (break) - - (let ((fd-list (if (null? fd-list) '() (car fd-list)))) + (call-with-current-continuation + (lambda (break) + + (let ((fd-list (if (null? fd-list) '() (car fd-list)))) - (let loop () + (let loop () - (let* ((next-jobs (find-next-jobs)) - (next-time (car next-jobs)) - (next-jobs-list (cdr next-jobs)) - (sleep-time (if next-time (- next-time (current-time)) - 2000000000))) + (let* ((next-jobs (find-next-jobs)) + (next-time (car next-jobs)) + (next-jobs-list (cdr next-jobs)) + (sleep-time (if next-time (- next-time (current-time)) + 2000000000))) - (and (> sleep-time 0) - (if (not (null? (car (select fd-list '() '() sleep-time)))) - (break))) - - (run-jobs next-jobs-list) + (and (> sleep-time 0) + (if (not (null? + (catch 'system-error + (lambda () + (car (select fd-list '() '() sleep-time))) + (lambda (key . args) ;; Exception add by Sergey + ;; Poznyakoff. + (if (member (car (last args)) + (list EINTR EAGAIN)) + (begin + (child-cleanup) '()) + (apply throw key args)))))) + (break))) - (do () ((or (<= number-children 0) - (eqv? (car (waitpid WAIT_ANY WNOHANG)) 0))) - (set! number-children (- number-children 1))) - - (loop))))))) + (run-jobs next-jobs-list) + + (child-cleanup) + + (loop))))))) diff --git a/mcron.c.template b/mcron.c.template index 4612f67..d9b1b16 100644 --- a/mcron.c.template +++ b/mcron.c.template @@ -53,6 +53,7 @@ +#include #include #include diff --git a/mcron.texinfo.in b/mcron.texinfo.in index ce4c11a..9bc4084 100644 --- a/mcron.texinfo.in +++ b/mcron.texinfo.in @@ -1,36 +1,28 @@ \input texinfo @c %**start of header @setfilename mcron.info -@settitle mcron 1.0.2 +@settitle mcron @VERSION@ @c %**end of header @syncodeindex fn cp -@copying -Copyright (C) 2003, 2005 Dale Mellor -This is free software. See the source files for the terms of the -copyright. +@copying This manual is for GNU mcron (version @VERSION@), which is a +program for running jobs at scheduled times. -@ignore -Permission is granted to make and distribute verbatim copies of -this manual provided the copyright notice and this permission notice -are preserved on all copies. +Copyright @copyright{} 2003, 2005, 2006 Dale Mellor -Permission is granted to process this file through TeX and print the -results, provided the printed document carries copying permission -notice identical to this one except for the removal of this paragraph -(this paragraph not being relevant to the printed manual). +@quotation +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 or +any later version published by the Free Software Foundation; with no +Invariant Sections, with the Front-Cover Texts being ``A GNU Manual,'' +and with the Back-Cover Texts as in (a) below. A copy of the +license is included in the section entitled ``GNU Free Documentation +License.'' -Permission is granted to copy and distribute modified versions of this -manual under the conditions for verbatim copying, provided that the entire -resulting derived work is distributed under the terms of a permission -notice identical to this one. - -Permission is granted to copy and distribute translations of this manual -into another language, under the above conditions for modified versions, -except that this permission notice may be stated in a translation approved -by the Foundation. -@end ignore +(a) The FSF's Back-Cover Text is: ``You have freedom to copy and modify +this GNU Manual, like GNU software.'' +@end quotation @end copying @@ -105,9 +97,9 @@ Vixie Detailed invoking -* Running mcron:: -* Running cron or crond:: -* Running crontab:: +* Invoking mcron:: +* Invoking cron or crond:: +* Invoking crontab:: * Behaviour on laptops:: * Exit codes:: @@ -140,7 +132,10 @@ time of the next command is computed. Furthermore, the specifications are written in scheme, allowing at the same time simple command execution instructions and very much more flexible ones to be composed than the original Vixie format. This has several useful advantages -over the original idea. +over the original idea. (Changes to user crontabs are signalled +directly to mcron by the crontab program; cron must still scan the +/etc/crontab file once every minute, although use of this file is +highly discouraged and this behaviour can be turned off). @cindex advantages of mcron @itemize @bullet @@ -179,7 +174,8 @@ more flexibility, and complete compatibility with Vixie cron. @end itemize A full discussion of the design and philosophy of mcron can be found -in the white paper at http://www.gnu.org/software/mcron/design.html. +in the white paper at +@url{http://www.gnu.org/software/mcron/design.html}. @node Simple examples, Syntax, Introduction, Top @@ -259,7 +255,7 @@ 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{cron} daemon must be already running -on your system, by root. +on your system, as root. @node Syntax, Invoking, Simple examples, Top @chapter Full available syntax @@ -441,17 +437,6 @@ the student to understand how this works!). "my-program") @end example -@cindex daylight savings time -Note that this example is also instructive in that it demonstrates -mcron's indeterminacy when the clocks are adjusted for summertime; use -the @code{-s 12} option to @code{mcron}, and see the off-by-one hour -error that occurs twice a year. This is a known problem, that -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). - - @node Two hours every day, Missing the first appointment, Every second Sunday, Extended Guile examples @subsection Two hours every day @@ -590,7 +575,7 @@ user. @node Crontab file, Incompatibilities with old Unices, Paul Vixie's copyright, Vixie Syntax -@subsection Crontab files. +@subsection Crontab files @cindex crontab file @cindex vixie crontab file A @code{crontab} file contains instructions to the @code{cron} daemon @@ -745,7 +730,7 @@ MAILTO=paul @end example @node Incompatibilities with old Unices, , Crontab file, Vixie Syntax -@subsection Extensions and incompatibilities. +@subsection Extensions and incompatibilities @cindex incompatibilities with old Unices @cindex extensions, vixie over old Unices This section lists differences between Paul Vixie's cron and the @@ -813,15 +798,15 @@ place in the part which implements the mcron personality. @menu -* Running mcron:: -* Running cron or crond:: -* Running crontab:: +* Invoking mcron:: +* Invoking cron or crond:: +* Invoking crontab:: * Behaviour on laptops:: * Exit codes:: @end menu -@node Running mcron, Running cron or crond, Invoking, Invoking -@section Running mcron +@node Invoking mcron, Invoking cron or crond, Invoking, Invoking +@section Invoking mcron @cindex invoking mcron @cindex mcron options @cindex mcron arguments @@ -903,12 +888,12 @@ standard output. @end table -@node Running cron or crond, Running crontab, Running mcron, Invoking -@section Running cron or crond +@node Invoking cron or crond, Invoking crontab, Invoking mcron, Invoking +@section Invoking cron or crond @cindex cron, invokation -@cindex running cron +@cindex invoking cron @cindex crond, invokation -@cindex running crond +@cindex invoking crond @cindex @CONFIG_SPOOL_DIR@ @cindex @CONFIG_SOCKET_FILE@ NOTE THAT THIS SECTION ONLY APPLIES IF THE @code{cron} or @@ -979,10 +964,10 @@ recommended that this option be used (and further that the @end table -@node Running crontab, Behaviour on laptops, Running cron or crond, Invoking -@section Running crontab +@node Invoking crontab, Behaviour on laptops, Invoking cron or crond, Invoking +@section Invoking crontab @cindex crontab, invoking -@cindex running crontab +@cindex invoking crontab This program is run by individual users to inspect or modify their crontab files. If a change is made to the file, then the root daemon process will be given a kick, and will immediately read the new @@ -1046,7 +1031,7 @@ become immediately effective. @end table -@node Behaviour on laptops, Exit codes, Running crontab, Invoking +@node Behaviour on laptops, Exit codes, Invoking crontab, Invoking @section Behaviour on laptops @cindex laptops @cindex power suspend diff --git a/vixie-specification.scm b/vixie-specification.scm index 08a8699..0bf4328 100644 --- a/vixie-specification.scm +++ b/vixie-specification.scm @@ -54,8 +54,8 @@ (define (parse-user-vixie-line line) (let ((match (regexp-exec parse-user-vixie-line-regexp line))) - (if (not match) (begin (display "Bad job line in Vixie file.\n") - (primitive-exit 10))) + (if (not match) + (throw 'mcron-error 10 "Bad job line in Vixie file.")) (job (match:substring match 1) (lambda () (with-mail-out (match:substring match 3))) (match:substring match 3)))) @@ -71,8 +71,8 @@ (define (parse-system-vixie-line 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))) + (if (not match) + (throw 'mcron-error 11 "Bad job line in /etc/crontab.")) (let ((user (match:substring match 3))) (set-configuration-user user) (job (match:substring match 1) @@ -92,7 +92,7 @@ "^[ \t]*([[:alpha:]_][[:alnum:]_]*)[ \t]*=[ \t]*\"(.*)\"[ \t]*$")) (define parse-vixie-environment-regexp2 (make-regexp - "^[ \t]*([[:alpha:]_][[:alnum:]_]*)[ \t]*=[ \t]*\'(.*)\'[ \t]*$")) + "^[ \t]*([[:alpha:]_][[:alnum:]_]*)[ \t]*=[ \t]*'(.*)'[ \t]*$")) (define parse-vixie-environment-regexp3 (make-regexp "^[ \t]*([[:alpha:]_][[:alnum:]_]*)[ \t]*=[ \t]*(.*[^ \t])[ \t]*$")) @@ -136,26 +136,39 @@ (let ((parse-vixie-line (if (null? parse-vixie-line) parse-user-vixie-line (car parse-vixie-line)))) - (do ((line (read-line port) (read-line port))) + (do ((line (read-line port) (read-line port)) + (line-number 1 (1+ line-number))) ((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)) - #\\)) - (let ((next-line (read-line port))) - (if (eof-object? next-line) - (set! next-line "")) - (set! line - (string-append - (substring line 0 (- (string-length line) 1)) - next-line)))) - ;; Consider the three cases mentioned in the description. - (or (regexp-exec read-vixie-file-comment-regexp line) - (parse-vixie-environment line) - (parse-vixie-line line)))))) + (let ((report-line line-number)) + ;; If the line ends with \, append the next line. + (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 "")) + (set! line-number (1+ line-number)) + (set! line + (string-append + (substring line 0 (- (string-length line) 1)) + next-line)))) + + (catch 'mcron-error + (lambda () + ;; Consider the three cases mentioned in the description. + (or (regexp-exec read-vixie-file-comment-regexp line) + (parse-vixie-environment line) + (parse-vixie-line line))) + (lambda (key exit-code . msg) + (throw + 'mcron-error + exit-code + (apply string-append + (number->string report-line) + ": " + msg))))))))) @@ -168,12 +181,16 @@ (catch #t (lambda () (set! port (open-input-file file-path))) (lambda (key . args) (set! port #f))) (if port - (begin - (if (null? parse-vixie-line) - (read-vixie-port port) - (read-vixie-port port (car parse-vixie-line))) - (close port))))) - + (catch 'mcron-error + (lambda () + (if (null? parse-vixie-line) + (read-vixie-port port) + (read-vixie-port port (car parse-vixie-line))) + (close port)) + (lambda (key exit-code . msg) + (close port) + (throw 'mcron-error exit-code + (apply string-append file-path ":" msg))))))) ;; A procedure which determines if the /etc/crontab file has been recently diff --git a/vixie-time.scm b/vixie-time.scm index 164a8de..f8b74d1 100644 --- a/vixie-time.scm +++ b/vixie-time.scm @@ -92,8 +92,8 @@ 1)) ;; [1] (let ((match (regexp-exec parse-vixie-subelement-regexp string))) (cond ((not match) - (display "Error: Bad Vixie-style time specification.\n") - (primitive-exit 9)) + (throw 'mcron-error 9 + "Bad Vixie-style time specification.")) ((match:substring match 5) (range (string->number (match:substring match 1)) (+ 1 (string->number (match:substring match 3))) @@ -271,7 +271,14 @@ ;; ;; We start by computing a list of time-spec objects (described above) for the ;; minute, hour, date, month, year and weekday components of the overall time -;; specification [1]. When we create the return procedure, it is this list to +;; specification [1]. Special care is taken to produce proper values for +;; fields 2 and 4: according to Vixie specification "If both fields are +;; restricted (ie, aren't *), the command will be run when _either_ field +;; matches the current time." This implies that if one of these fields is *, +;; while the other is not, its value should be '() [0], otherwise +;; interpolate-weekdays below will produce incorrect results. + +;; When we create the return procedure, it is this list to ;; 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 @@ -296,61 +303,84 @@ ;; through the higher components if necessary [6]. We now have the next time ;; the command needs to run. ;; -;; The new time is then converted back into a UNIX time, and returned [7]. +;; The new time is then converted back into a UNIX time and returned [7]. (define (parse-vixie-time string) - (let* ((tokens (string-tokenize (vixie-substitute-parse-symbols string))) - (time-spec-list - (map-in-order (lambda (x) (vector (parse-vixie-element - (list-ref tokens (vector-ref x 0)) - (vector-ref x 1) - (vector-ref x 2)) - (vector-ref x 3) - (vector-ref x 4))) - ;; token range-top+1 getter setter + (let ((tokens (string-tokenize (vixie-substitute-parse-symbols string)))) + (cond + ((> (length tokens) 5) + (throw 'mcron-error 9 + "Too many fields in Vixie-style time specification")) + ((< (length tokens) 5) + (throw 'mcron-error 9 + "Not enough fields in Vixie-style time specification"))) + (let ((time-spec-list + (map-in-order (lambda (x) (vector + (let* ((n (vector-ref x 0)) + (tok (list-ref tokens n))) + (cond + ((and (= n 4) + (string=? tok "*") + (not (string=? + (list-ref tokens 2) "*"))) + '()) + ((and (= n 2) + (string=? tok "*") + (not (string=? + (list-ref tokens 4) "*"))) + '()) + (else + (parse-vixie-element + tok + (vector-ref x 1) + (vector-ref x 2))))) ; [0] + (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 ) #( 2 1 32 ,tm:mday ,set-tm:mday ) #( 3 0 12 ,tm:mon ,set-tm:mon ) - #( 4 0 7 ,tm:wday ,set-tm:wday ))))) ;; [1] + #( 4 0 7 ,tm:wday ,set-tm:wday ))))) ;; [1] - (vector-set! (car (last-pair time-spec-list)) - 0 - (map (lambda (time-spec) - (if (eqv? time-spec 7) 0 time-spec)) - (vector-ref (car (last-pair time-spec-list)) 0))) ;; [2] + (vector-set! (car (last-pair time-spec-list)) + 0 + (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] - - (if (not (member (tm:mon time) - (time-spec:list (cadddr time-spec-list)))) - (begin - (nudge-month! time (cdddr 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))) - (if (not (member (tm:hour time) - (time-spec:list (cadr time-spec-list)))) - (begin - (nudge-hour! time (cdr time-spec-list)) - (set-tm:min time -1))) ;; [5] + (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] + + (if (not (member (tm:mon time) + (time-spec:list (cadddr time-spec-list)))) + (begin + (nudge-month! time (cdddr 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))) + (if (not (member (tm:hour time) + (time-spec:list (cadr time-spec-list)))) + (begin + (nudge-hour! time (cdr time-spec-list)) + (set-tm:min time -1))) ;; [5] + + (set-tm:sec time 0) + (nudge-min! time time-spec-list) ;; [6] + (car (mktime time))))))) ;; [7] - (set-tm:sec time 0) - (nudge-min! time time-spec-list) ;; [6] - (car (mktime time)))))) ;; [7] From 651f3b4a6bf78c87a1ab453f8489441b919a1ca3 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Fri, 25 Jan 2008 21:49:16 +0000 Subject: [PATCH 013/239] Removed target-specific compiler flags from makefile. --- ChangeLog | 11 ++++++++++- makefile.am | 6 ++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9f57f57..2547e37 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,13 @@ -2005-09-02 hydro23 > +2008-01-25 Dale Mellor > + + * makefile.am: Moved target-specific CFLAGS and LDFLAGS to global + AM_* variables, to remove problem with automake requiring + AM_PROGS_CC_C_O in configure.ac (!) + + * Version is currently at 1.0.3. + + +2005-09-02 hydro23 > * makefile.am, mcron.c.template (main): Modified install-exec-hook so that a proper installation of a Vixie-compatible cron only diff --git a/makefile.am b/makefile.am index b3d32d8..afeafe8 100644 --- a/makefile.am +++ b/makefile.am @@ -30,11 +30,13 @@ EXTRA_DIST = makefile.ed main.scm mcron-core.scm vixie-specification.scm \ crontab.scm environment.scm job-specifier.scm redirect.scm \ vixie-time.scm mcron.c.template BUGS +AM_LDFLAGS = @GUILE_LDFLAGS@ +AM_CFLAGS = @GUILE_CFLAGS@ -DGUILE_LOAD_PATH=\"$(datadir)\" + info_TEXINFOS = mcron.texinfo + bin_PROGRAMS = mcron mcron_SOURCES = mcron.c -mcron_LDFLAGS = @GUILE_LDFLAGS@ -mcron_CFLAGS = @GUILE_CFLAGS@ -DGUILE_LOAD_PATH=\"$(datadir)\" pkgdata_DATA = core.scm environment.scm job-specifier.scm redirect.scm \ vixie-time.scm vixie-specification.scm config.scm From eb041a75325650e3953c5cc2ad70172e93283d3b Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Fri, 25 Jan 2008 21:59:21 +0000 Subject: [PATCH 014/239] The --schedule argument is no longer optional. --- ChangeLog | 5 +++++ main.scm | 18 ++++++------------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2547e37..8fb1eb7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2008-01-25 Dale Mellor > + * main.scm: Argument to --schedule is no longer optional (the + options system goes really screwy with optional values, usually + pulling the first non-option argument as a value if one was not + intended!) + * makefile.am: Moved target-specific CFLAGS and LDFLAGS to global AM_* variables, to remove problem with automake requiring AM_PROGS_CC_C_O in configure.ac (!) diff --git a/main.scm b/main.scm index 9017276..9424736 100644 --- a/main.scm +++ b/main.scm @@ -106,12 +106,10 @@ (edit (single-char #\e) (value #f)) (list (single-char #\l) (value #f)) (remove (single-char #\r) (value #f)))) - (else `((schedule (single-char #\s) - (value optional) - (predicate ;; Added by Sergey Poznyakoff. + (else `((schedule (single-char #\s) (value #t) + (predicate ,(lambda (value) - (or (eq? value #t) - (string->number value))))) + (string->number value)))) (daemon (single-char #\d) (value #f)) (noetc (single-char #\n) (value #f)) (stdin (single-char #\i) (value #t) @@ -157,8 +155,7 @@ extensions.\n \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 mcron\n + -sN, --schedule[=]N Display the next N jobs that will be run by mcron\n -d, --daemon Immediately detach the program from the terminal and\n run as a daemon process\n -i, --stdin=(guile|vixie) Format of data passed as standard input or\n @@ -171,8 +168,7 @@ reading all the information in the users' crontabs and in /etc/crontab.\n \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\n + -sN, --schedule[=]N Display the next N jobs that will be run by cron\n -n, --noetc Do not check /etc/crontab for updates (HIGHLY\n RECOMMENDED).") @@ -403,9 +399,7 @@ option.\n") ;; count is some positive integer. (and-let* ((count (option-ref options 'schedule #f))) - (set! count (if (eq? count #t) - 8 - (string->number count))) + (set! count (string->number count)) (display (get-schedule (if (<= count 0) 1 count))) (quit)) From 3094f9b7912ede3f5fc85d97feab1b327960df12 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Sat, 26 Jan 2008 10:50:59 +0000 Subject: [PATCH 015/239] Allow files named on command line to have arbitrary names (assume guile input format). --- ChangeLog | 4 ++++ main.scm | 11 ++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8fb1eb7..4e364b4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2008-01-25 Dale Mellor > + * main.scm (command-type): Files which are listed on the command + line are assumed to be guile configurations if they do not end in + .guile or .vixie (previously they were silently ignored). + * main.scm: Argument to --schedule is no longer optional (the options system goes really screwy with optional values, usually pulling the first non-option argument as a value if one was not diff --git a/main.scm b/main.scm index 9424736..f1269d0 100644 --- a/main.scm +++ b/main.scm @@ -283,15 +283,16 @@ Report bugs to " config-package-bugreport ".\n (define guile-file-regexp (make-regexp "\\.gui(le)?$")) (define vixie-file-regexp (make-regexp "\\.vix(ie)?$")) -(define (process-user-file file-path) +(define (process-user-file file-path . assume-guile) (cond ((string=? file-path "-") (if (string=? (option-ref options 'stdin "guile") "vixie") (read-vixie-port (current-input-port)) (eval-string (stdin->string)))) - ((regexp-exec guile-file-regexp file-path) - (load file-path)) + ((or (not (null? assume-guile)) + (regexp-exec guile-file-regexp file-path)) + (load file-path)) ((regexp-exec vixie-file-regexp file-path) - (read-vixie-file file-path)))) + (read-vixie-file file-path)))) @@ -368,7 +369,7 @@ Report bugs to " config-package-bugreport ".\n ((mcron) (if (null? (option-ref options '() '())) (process-files-in-user-directory) (for-each (lambda (file-path) - (process-user-file file-path)) + (process-user-file file-path #t)) (option-ref options '() '())))) ((cron) (process-files-in-system-directory) From 6c34d042b9e2731db1d8f6a8e9bf88e4ed8394bb Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Thu, 21 Feb 2008 19:11:23 +0000 Subject: [PATCH 016/239] Upgrade to GPLv3 and bump version to 1.0.4. --- .gitignore | 1 + COPYING | 674 ++++++++++++++++++++++++++++++++++++++++ ChangeLog | 16 +- NEWS | 6 + README | 2 +- config.scm.in | 26 +- configure.ac | 32 +- crontab.scm | 26 +- environment.scm | 26 +- job-specifier.scm | 26 +- main.scm | 26 +- makefile.am | 29 +- makefile.ed | 24 +- mcron-core.scm | 26 +- mcron.c.template | 26 +- redirect.scm | 26 +- vixie-specification.scm | 26 +- vixie-time.scm | 27 +- 18 files changed, 868 insertions(+), 177 deletions(-) create mode 100644 .gitignore create mode 100644 COPYING diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b25c15b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/ChangeLog b/ChangeLog index 4e364b4..c47a49e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,14 @@ -2008-01-25 Dale Mellor > +2008-02-21 Dale Mellor + + * ALL FILES: Replaced version 2 GPL notices with version 3 ones. + + * makefile.am: Do not remove COPYING file with make + maintainer-clean; if you do it will eventually get replaced with + the old version 2 GPL by a subsequent automake. + + * configure.ac: Bumped version to 1.0.4. + +2008-01-25 Dale Mellor * main.scm (command-type): Files which are listed on the command line are assumed to be guile configurations if they do not end in @@ -16,7 +26,7 @@ * Version is currently at 1.0.3. -2005-09-02 hydro23 > +2005-09-02 hydro23 * makefile.am, mcron.c.template (main): Modified install-exec-hook so that a proper installation of a Vixie-compatible cron only @@ -110,7 +120,7 @@ ________________________________________________________________________________ -Copyright (C) 2003 Dale Mellor +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 diff --git a/NEWS b/NEWS index 8663d8f..6809a76 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,12 @@ See the end for copying conditions. Please send bug reports to bug-mcron@gnu.org. +Thursday, 21st Februrary 2008 + + Released version 1.0.4, under the new GPLv3 license, after some prodding by + Karl Berry. + + Sunday, 16th April 2006 Released version 1.0.3. Incorporated many coding suggestions by Sergey Poznyakoff, which makes the program work with daylight savings time shifts, diff --git a/README b/README index 41c6092..c44f0c5 100644 --- a/README +++ b/README @@ -2,7 +2,7 @@ Copyright (C) 2003 Dale Mellor -*-text-*- See the end for copying conditions. -This is version 1.0.3 of the GNU mcron program. It is designed and written by +This is version 1.0.4 of the GNU mcron program. It is designed and written by Dale Mellor, and 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 diff --git a/config.scm.in b/config.scm.in index 2ccbd49..6a0a85d 100644 --- a/config.scm.in +++ b/config.scm.in @@ -2,20 +2,20 @@ ;; Copyright (C) 2003 Dale Mellor ;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) +;; This file is part of GNU mcron. +;; +;; GNU mcron is free software: you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation, either version 3 of the License, or (at your option) ;; any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this program; if not, write to the Free Software -;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -;; USA. +;; +;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +;; more details. +;; +;; You should have received a copy of the GNU General Public License along +;; with GNU mcron. If not, see . ;; Some constants set by the configuration process. diff --git a/configure.ac b/configure.ac index cf11ad4..3253535 100644 --- a/configure.ac +++ b/configure.ac @@ -4,24 +4,24 @@ # Copyright (C) 2003, 2005 Dale Mellor # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -# USA. +# This file is part of GNU mcron. +# +# GNU mcron is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU mcron is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with GNU mcron. If not, see . -AC_PREREQ(2.59) -AC_INIT([mcron], [1.0.3], [dale_mellor@users.sourceforge.net]) +AC_PREREQ(2.61) +AC_INIT([mcron], [1.0.4], [dale_mellor@users.sourceforge.net]) AM_INIT_AUTOMAKE diff --git a/crontab.scm b/crontab.scm index 96d8b3c..ff74947 100644 --- a/crontab.scm +++ b/crontab.scm @@ -1,19 +1,19 @@ ;; Copyright (C) 2003 Dale Mellor ;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) +;; This file is part of GNU mcron. +;; +;; GNU mcron is free software: you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation, either version 3 of the License, or (at your option) ;; any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this program; if not, write to the Free Software -;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -;; USA. +;; +;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +;; more details. +;; +;; You should have received a copy of the GNU General Public License along +;; with GNU mcron. If not, see . ;; Apart from the collecting of options and the handling of --help and --version diff --git a/environment.scm b/environment.scm index 82c3a27..9f694f1 100644 --- a/environment.scm +++ b/environment.scm @@ -1,19 +1,19 @@ ;; Copyright (C) 2003 Dale Mellor ;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) +;; This file is part of GNU mcron. +;; +;; GNU mcron is free software: you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation, either version 3 of the License, or (at your option) ;; any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this program; if not, write to the Free Software -;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -;; USA. +;; +;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +;; more details. +;; +;; You should have received a copy of the GNU General Public License along +;; with GNU mcron. If not, see . diff --git a/job-specifier.scm b/job-specifier.scm index 52e655f..cce948c 100644 --- a/job-specifier.scm +++ b/job-specifier.scm @@ -1,19 +1,19 @@ ;; Copyright (C) 2003 Dale Mellor ;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) +;; This file is part of GNU mcron. +;; +;; GNU mcron is free software: you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation, either version 3 of the License, or (at your option) ;; any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this program; if not, write to the Free Software -;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -;; USA. +;; +;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +;; more details. +;; +;; You should have received a copy of the GNU General Public License along +;; with GNU mcron. If not, see . diff --git a/main.scm b/main.scm index f1269d0..5470a55 100644 --- a/main.scm +++ b/main.scm @@ -1,19 +1,19 @@ ;; Copyright (C) 2003 Dale Mellor ;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) +;; This file is part of GNU mcron. +;; +;; GNU mcron is free software: you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation, either version 3 of the License, or (at your option) ;; any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this program; if not, write to the Free Software -;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -;; USA. +;; +;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +;; more details. +;; +;; You should have received a copy of the GNU General Public License along +;; with GNU mcron. If not, see . diff --git a/makefile.am b/makefile.am index afeafe8..e4c441f 100644 --- a/makefile.am +++ b/makefile.am @@ -1,19 +1,20 @@ ## Makefile for the toplevel directory of mcron. ## Copyright (C) 2003 Dale Mellor ## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2, or (at your option) -## any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# This file is part of GNU mcron. +# +# GNU mcron is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU mcron is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with GNU mcron. If not, see . ## Process this file with automake to produce Makefile.in @@ -22,7 +23,7 @@ CP = @CP@ MAINTAINERCLEANFILES = configure makefile makefile.in config.guess config.sub \ install-sh missing mkinstalldirs texinfo.tex INSTALL \ - aclocal.m4 compile depcomp COPYING + aclocal.m4 compile depcomp CLEANFILES = mcron.c core.scm diff --git a/makefile.ed b/makefile.ed index af1299b..5c89344 100644 --- a/makefile.ed +++ b/makefile.ed @@ -1,19 +1,19 @@ # Copyright (C) 2003 Dale Mellor # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. +# This file is part of GNU mcron. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# GNU mcron is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -# USA. +# GNU mcron is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with GNU mcron. If not, see . # # # diff --git a/mcron-core.scm b/mcron-core.scm index b8ca289..518bcac 100644 --- a/mcron-core.scm +++ b/mcron-core.scm @@ -1,19 +1,19 @@ ;; Copyright (C) 2003 Dale Mellor ;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) +;; This file is part of GNU mcron. +;; +;; GNU mcron is free software: you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation, either version 3 of the License, or (at your option) ;; any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this program; if not, write to the Free Software -;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -;; USA. +;; +;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +;; more details. +;; +;; You should have received a copy of the GNU General Public License along +;; with GNU mcron. If not, see . diff --git a/mcron.c.template b/mcron.c.template index d9b1b16..cba503e 100644 --- a/mcron.c.template +++ b/mcron.c.template @@ -2,20 +2,20 @@ /* * Copyright (C) 2003 Dale Mellor * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) + * This file is part of GNU mcron. + * + * GNU mcron is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. + * + * GNU mcron is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with GNU mcron. If not, see . */ diff --git a/redirect.scm b/redirect.scm index 0e10b40..312b768 100644 --- a/redirect.scm +++ b/redirect.scm @@ -1,19 +1,19 @@ ;; Copyright (C) 2003 Dale Mellor ;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) +;; This file is part of GNU mcron. +;; +;; GNU mcron is free software: you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation, either version 3 of the License, or (at your option) ;; any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this program; if not, write to the Free Software -;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -;; USA. +;; +;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +;; more details. +;; +;; You should have received a copy of the GNU General Public License along +;; with GNU mcron. If not, see . diff --git a/vixie-specification.scm b/vixie-specification.scm index 0bf4328..ab002ba 100644 --- a/vixie-specification.scm +++ b/vixie-specification.scm @@ -1,19 +1,19 @@ ;; Copyright (C) 2003 Dale Mellor ;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) +;; This file is part of GNU mcron. +;; +;; GNU mcron is free software: you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation, either version 3 of the License, or (at your option) ;; any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this program; if not, write to the Free Software -;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -;; USA. +;; +;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +;; more details. +;; +;; You should have received a copy of the GNU General Public License along +;; with GNU mcron. If not, see . diff --git a/vixie-time.scm b/vixie-time.scm index f8b74d1..2f26a6d 100644 --- a/vixie-time.scm +++ b/vixie-time.scm @@ -1,20 +1,19 @@ ;; Copyright (C) 2003 Dale Mellor ;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) +;; This file is part of GNU mcron. +;; +;; GNU mcron is free software: you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation, either version 3 of the License, or (at your option) ;; any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this program; if not, write to the Free Software -;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -;; USA. - +;; +;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +;; more details. +;; +;; You should have received a copy of the GNU General Public License along +;; with GNU mcron. If not, see . (define-module (mcron vixie-time) From 0cbb22fd196a6c232eff37acf9e16f1299aa0252 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Thu, 21 Feb 2008 21:26:46 +0000 Subject: [PATCH 017/239] Made NEWS about the savannah GIT repository. --- NEWS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS b/NEWS index 6809a76..32599ce 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,9 @@ Please send bug reports to bug-mcron@gnu.org. Thursday, 21st Februrary 2008 + The source code is now held in a GIT repository, at + git://git.savannah.gnu.org/mcron.git. + Released version 1.0.4, under the new GPLv3 license, after some prodding by Karl Berry. From 9fe5fddf30cb159e959295d4ec979678b0130a9c Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Sat, 12 Jun 2010 22:39:20 +0100 Subject: [PATCH 018/239] Added a simple man page using help2man (the generation is _not_ automatic through the makefile). --- makefile.am | 3 ++- mcron.1 | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 mcron.1 diff --git a/makefile.am b/makefile.am index e4c441f..9f9b59d 100644 --- a/makefile.am +++ b/makefile.am @@ -36,6 +36,8 @@ AM_CFLAGS = @GUILE_CFLAGS@ -DGUILE_LOAD_PATH=\"$(datadir)\" info_TEXINFOS = mcron.texinfo +dist_man1_MANS = mcron.1 + bin_PROGRAMS = mcron mcron_SOURCES = mcron.c @@ -86,4 +88,3 @@ uninstall-hook: if [ "`id -u`" -eq "0" ]; then \ rm -f $(fpp){cron,crontab}$(EXEEXT); \ fi - diff --git a/mcron.1 b/mcron.1 new file mode 100644 index 0000000..e93d491 --- /dev/null +++ b/mcron.1 @@ -0,0 +1,50 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. +.TH MCRON "1" "June 2010" "mcron " "User Commands" +.SH NAME +mcron \- manual page for mcron +.SH SYNOPSIS +.B mcron +[\fIOPTIONS\fR] [\fIFILES\fR] +.SH DESCRIPTION +Run an mcron process according to the specifications in the FILES (`\-' for +standard input), or use all the files in ~/.cron with .guile or .vixie +extensions. +.TP +\fB\-v\fR, \fB\-\-version\fR +Display version +.TP +\fB\-h\fR, \fB\-\-help\fR +Display this help message +.TP +\fB\-sN\fR, \fB\-\-schedule[\fR=\fI]N\fR +Display the next N jobs that will be run by mcron +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Immediately detach the program from the terminal and +run as a daemon process +.TP +\fB\-i\fR, \fB\-\-stdin=\fR(guile|vixie) Format of data passed as standard input or +file arguments (default guile) +.SH AUTHOR +Written by Dale Mellor +.SH "REPORTING BUGS" +Report bugs to dale_mellor@users.sourceforge.net. +.PP +mcron (mcron 1.0.4) +.SH COPYRIGHT +Copyright \(co 2003, 2006 Dale Mellor +.br +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +.SH "SEE ALSO" +The full documentation for +.B mcron +is maintained as a Texinfo manual. If the +.B info +and +.B mcron +programs are properly installed at your site, the command +.IP +.B info mcron +.PP +should give you access to the complete manual. From f76377aa373b9553836e84402015d4da6685a184 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Sat, 12 Jun 2010 22:57:55 +0100 Subject: [PATCH 019/239] Removed makefile dependence on mkinstalldirs, which was supplied by an earlier version of automake. --- makefile.am | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/makefile.am b/makefile.am index 9f9b59d..dee61af 100644 --- a/makefile.am +++ b/makefile.am @@ -22,7 +22,7 @@ ED = @ED@ # !!!! Are these needed? CP = @CP@ MAINTAINERCLEANFILES = configure makefile makefile.in config.guess config.sub \ - install-sh missing mkinstalldirs texinfo.tex INSTALL \ + install-sh missing texinfo.tex INSTALL \ aclocal.m4 compile depcomp CLEANFILES = mcron.c core.scm @@ -50,41 +50,34 @@ pkgdata_DATA = core.scm environment.scm job-specifier.scm redirect.scm \ # of this). core.scm : mcron-core.scm - $(CP) mcron-core.scm core.scm + $(CP) mcron-core.scm core.scm mcron.c : main.scm crontab.scm makefile.ed mcron.c.template - @echo 'Building mcron.c...' - @$(ED) < makefile.ed > /dev/null 2>&1 - @rm -f mcron.escaped.scm > /dev/null 2>&1 + @echo 'Building mcron.c...' + @$(ED) < makefile.ed > /dev/null 2>&1 + @rm -f mcron.escaped.scm > /dev/null 2>&1 -# !!!! Want to be able to install as non-root. - -# install-exec-local: -# @if [ `id -u` -ne 0 ]; then \ -# echo "*** MUST BE ROOT TO INSTALL MCRON ***"; \ -# exit 1; \ -# fi - #full program prefix fpp = $(DESTDIR)$(bindir)/@real_program_prefix@ + install-exec-hook: - @if [ "`id -u`" -eq "0" ]; then \ - 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; \ - ./mkinstalldirs -m 'u=rwx,og=rx' @GUILE_SITE@; \ - ./mkinstalldirs -m 'u=rwx,og=rx' @GUILE_SITE@/mcron; \ + @if [ "`id -u`" -eq "0" ]; then \ + 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); \ + $(INSTALL) -d --mode='u=rwx' /var/cron; \ + $(INSTALL) -d --mode='u=rwx,og=rx' /var/run; \ + $(INSTALL) -d --mode='u=rwx,og=rx' @GUILE_SITE@; \ + $(INSTALL) -d --mode='u=rwx,og=rx' @GUILE_SITE@/mcron; \ else \ echo "+++ WARNING: NON-ROOT INSTALL: ONLY mcron WILL BE INSTALLED, NOT ANY OF THE VIXIE REPLACEMENT PROGRAMS"; \ - fi + fi uninstall-hook: - if [ "`id -u`" -eq "0" ]; then \ - rm -f $(fpp){cron,crontab}$(EXEEXT); \ - fi + if [ "`id -u`" -eq "0" ]; then \ + rm -f $(fpp){cron,crontab}$(EXEEXT); \ + fi From 323033546da8d2b00ef993223cc83b003e183aa0 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Sun, 13 Jun 2010 03:49:39 +0100 Subject: [PATCH 020/239] Added --enable-no-vixie-clobber to configure.ac. --- ChangeLog | 40 +++++++++++++++++++++++++++------------- configure.ac | 12 ++++++++++++ makefile.am | 14 ++++++++------ 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index c47a49e..049faf4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,17 @@ -2008-02-21 Dale Mellor +2010-06-13 Dale Mellor + + * configure.ac: added --enable-no-vixie-clobber argument to + configure so that the root user can avoid overwriting a legacy + cron installation. + + * mcron.1: added simple, minimal man page using help2man (the + texinfo file is still the primary documentation source). + + * makefile.am: replaced use of mkinstalldirs with install; the + former is not supplied with the latest automake (1.11). + + +2008-02-21 Dale Mellor * ALL FILES: Replaced version 2 GPL notices with version 3 ones. @@ -8,12 +21,13 @@ * configure.ac: Bumped version to 1.0.4. -2008-01-25 Dale Mellor + +2008-01-25 Dale Mellor * main.scm (command-type): Files which are listed on the command line are assumed to be guile configurations if they do not end in .guile or .vixie (previously they were silently ignored). - + * main.scm: Argument to --schedule is no longer optional (the options system goes really screwy with optional values, usually pulling the first non-option argument as a value if one was not @@ -24,9 +38,9 @@ AM_PROGS_CC_C_O in configure.ac (!) * Version is currently at 1.0.3. - -2005-09-02 hydro23 + +2005-09-02 Dale Mellor * makefile.am, mcron.c.template (main): Modified install-exec-hook so that a proper installation of a Vixie-compatible cron only @@ -41,7 +55,7 @@ laptop awakes from suspend mode). * Bumped version to 1.0.2. - + 2004-05-15 Dale Mellor @@ -49,7 +63,7 @@ properly homed at www.gnu.org. * Bumped version to 1.0.1. - + 2003-12-11 Dale Mellor @@ -58,7 +72,7 @@ * Bumped version to 1.0.0. - + 2003-12-07 Dale Mellor * configure.ac: Added switches for files and directories used by @@ -67,24 +81,24 @@ these configure options (including the source for the texinfo manual). - + 2003-12-05 Dale Mellor * configure.ac: Added test for guile version >= 1.6.4. * bumped version to 0.99.4. - + 2003-08-03 Dale Mellor * Third cut, fully functional, modular, production quality, still needs testing... - + * Pulled all functionality into modules, so it can be incorporated into other programs. * Bumped version to 0.99.3. - + 2003-07-20 Dale Mellor @@ -111,7 +125,7 @@ * Broken/incomplete Guile prevents vixie compatibility from working - this has been disabled by default in the configuration. - + * Version set at 0.99.1 diff --git a/configure.ac b/configure.ac index 3253535..aef53f5 100644 --- a/configure.ac +++ b/configure.ac @@ -105,6 +105,18 @@ fi SENDMAIL=$ac_cv_prog_SENDMAIL +# Find out if we are avoiding Vixie. + +AC_MSG_CHECKING([whether to avoid clobbering a Vixie installation]) +AC_ARG_ENABLE(no-vixie-clobber, + AC_HELP_STRING([--enable-no-vixie-clobber], + [do not install with program names that would override a legacy cron installation]), + NO_VIXIE_CLOBBER=$enableval, + NO_VIXIE_CLOBBER=[no]) +AC_MSG_RESULT($NO_VIXIE_CLOBBER) +AC_SUBST(NO_VIXIE_CLOBBER) + + # Configure the various files that mcron uses at runtime. AC_MSG_CHECKING([which spool directory to use]) diff --git a/makefile.am b/makefile.am index dee61af..8953729 100644 --- a/makefile.am +++ b/makefile.am @@ -50,12 +50,12 @@ pkgdata_DATA = core.scm environment.scm job-specifier.scm redirect.scm \ # of this). core.scm : mcron-core.scm - $(CP) mcron-core.scm core.scm + $(CP) mcron-core.scm core.scm mcron.c : main.scm crontab.scm makefile.ed mcron.c.template - @echo 'Building mcron.c...' - @$(ED) < makefile.ed > /dev/null 2>&1 - @rm -f mcron.escaped.scm > /dev/null 2>&1 + @echo 'Building mcron.c...' + @$(ED) < makefile.ed > /dev/null 2>&1 + @rm -f mcron.escaped.scm > /dev/null 2>&1 #full program prefix @@ -63,7 +63,7 @@ fpp = $(DESTDIR)$(bindir)/@real_program_prefix@ install-exec-hook: - @if [ "`id -u`" -eq "0" ]; then \ + @if [ "x@NO_VIXIE_CLOBBER@" != "xyes" -a "`id -u`" -eq "0" ]; then \ 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; \ @@ -72,12 +72,14 @@ install-exec-hook: $(INSTALL) -d --mode='u=rwx,og=rx' /var/run; \ $(INSTALL) -d --mode='u=rwx,og=rx' @GUILE_SITE@; \ $(INSTALL) -d --mode='u=rwx,og=rx' @GUILE_SITE@/mcron; \ + elif [ "x@NO_VIXIE_CLOBBER@" = "xyes" ]; then \ + echo "Not installing Vixie-style programs"; \ else \ echo "+++ WARNING: NON-ROOT INSTALL: ONLY mcron WILL BE INSTALLED, NOT ANY OF THE VIXIE REPLACEMENT PROGRAMS"; \ fi uninstall-hook: - if [ "`id -u`" -eq "0" ]; then \ + if [ "`id -u`" -eq "0" ]; then \ rm -f $(fpp){cron,crontab}$(EXEEXT); \ fi From 03e95be5d64e9445363cfa407460ac0efb81ba21 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Sun, 13 Jun 2010 03:52:35 +0100 Subject: [PATCH 021/239] Bumped version number to 1.0.5. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index aef53f5..191729a 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ AC_PREREQ(2.61) -AC_INIT([mcron], [1.0.4], [dale_mellor@users.sourceforge.net]) +AC_INIT([mcron], [1.0.5], [dale_mellor@users.sourceforge.net]) AM_INIT_AUTOMAKE From a5e51bfa85d7b53390691ed3ae7308a04b18607a Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Sun, 13 Jun 2010 04:32:51 +0100 Subject: [PATCH 022/239] Make sure $DESTDIR pervades the makefile. --- makefile.am | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/makefile.am b/makefile.am index 8953729..46dd170 100644 --- a/makefile.am +++ b/makefile.am @@ -68,10 +68,10 @@ install-exec-hook: $(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); \ - $(INSTALL) -d --mode='u=rwx' /var/cron; \ - $(INSTALL) -d --mode='u=rwx,og=rx' /var/run; \ - $(INSTALL) -d --mode='u=rwx,og=rx' @GUILE_SITE@; \ - $(INSTALL) -d --mode='u=rwx,og=rx' @GUILE_SITE@/mcron; \ + $(INSTALL) -d --mode='u=rwx' $(DESTDIR)/var/cron; \ + $(INSTALL) -d --mode='u=rwx,og=rx' $(DESTDIR)/var/run; \ + $(INSTALL) -d --mode='u=rwx,og=rx' $(DESTDIR)@GUILE_SITE@; \ + $(INSTALL) -d --mode='u=rwx,og=rx' $(DESTDIR)@GUILE_SITE@/mcron; \ elif [ "x@NO_VIXIE_CLOBBER@" = "xyes" ]; then \ echo "Not installing Vixie-style programs"; \ else \ From be34829b1be722b4a03a13d9576addc8f55e5859 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Sun, 13 Jun 2010 11:02:25 +0100 Subject: [PATCH 023/239] Fixed up makefile to provide rule to create man page (not done automatically), and to remove any installed info/dir files. --- makefile.am | 20 ++++++++++++++++++++ mcron.1 | 4 ++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/makefile.am b/makefile.am index 46dd170..32c12f8 100644 --- a/makefile.am +++ b/makefile.am @@ -77,9 +77,29 @@ install-exec-hook: else \ echo "+++ WARNING: NON-ROOT INSTALL: ONLY mcron WILL BE INSTALLED, NOT ANY OF THE VIXIE REPLACEMENT PROGRAMS"; \ fi + @echo + @echo " AFTER INSTALLATION, CONSIDER RUNNING make cook-up-man" + @echo uninstall-hook: if [ "`id -u`" -eq "0" ]; then \ rm -f $(fpp){cron,crontab}$(EXEEXT); \ fi + + +# Debian lintian barfs if we install an info top-level. + +install-data-hook: + if [ -f $(DESTDIR)$(infodir)/dir -o -f $(DESTDIR)$(infodir)/dir.gz ]; \ + then \ + rm $(DESTDIR)$(infodir)/dir*; \ + fi + + +# Not part of formal package building, but a rule for manual use to get the +# elemental man page. Will only work once the mcron program is installed. +cook-up-man: + help2man -n 'a program to run tasks at regular (or not) intervals' \ + $(fpp)mcron > mcron.1 + $(MAKE) install diff --git a/mcron.1 b/mcron.1 index e93d491..dacebc4 100644 --- a/mcron.1 +++ b/mcron.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. .TH MCRON "1" "June 2010" "mcron " "User Commands" .SH NAME -mcron \- manual page for mcron +mcron \- a program to run tasks at regular (or not) intervals .SH SYNOPSIS .B mcron [\fIOPTIONS\fR] [\fIFILES\fR] @@ -30,7 +30,7 @@ Written by Dale Mellor .SH "REPORTING BUGS" Report bugs to dale_mellor@users.sourceforge.net. .PP -mcron (mcron 1.0.4) +mcron (mcron 1.0.5) .SH COPYRIGHT Copyright \(co 2003, 2006 Dale Mellor .br From 5fead83069363fe8fbc9f707c3e6e2ca0e9d0f67 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Sun, 13 Jun 2010 16:58:46 +0100 Subject: [PATCH 024/239] Leave info/dir around; the Debian package has a patch to remove it. --- makefile.am | 9 --------- 1 file changed, 9 deletions(-) diff --git a/makefile.am b/makefile.am index 32c12f8..4474ffe 100644 --- a/makefile.am +++ b/makefile.am @@ -88,15 +88,6 @@ uninstall-hook: fi -# Debian lintian barfs if we install an info top-level. - -install-data-hook: - if [ -f $(DESTDIR)$(infodir)/dir -o -f $(DESTDIR)$(infodir)/dir.gz ]; \ - then \ - rm $(DESTDIR)$(infodir)/dir*; \ - fi - - # Not part of formal package building, but a rule for manual use to get the # elemental man page. Will only work once the mcron program is installed. cook-up-man: From cff1b7effabec532ce4f13adec71076b60ad8ac4 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Sun, 13 Jun 2010 17:01:22 +0100 Subject: [PATCH 025/239] Added .gitignore. --- .gitignore | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.gitignore b/.gitignore index b25c15b..e760631 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,21 @@ *~ +.deps +INSTALL +aclocal.m4 +autom4te.cache +config.log +config.scm +config.status +configure +core.scm +depcomp +install-sh +makefile +makefile.in +mcron +mcron.c +mcron.info +mcron.o +mcron.texinfo +missing +texinfo.tex From 0115be5d133d1e5252d9f05ece3c09ee350914ab Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Sat, 19 Jun 2010 21:52:22 +0100 Subject: [PATCH 026/239] Unified copyright notices in minor files, removed immutable page covers from texinfo file. --- AUTHORS | 10 ++++++++++ BUGS | 25 +++++++++---------------- ChangeLog | 14 ++++---------- NEWS | 43 +++++++++++++++++++++++++------------------ README | 27 ++++++++------------------- TODO | 23 +++++++---------------- configure.ac | 2 +- mcron.1 | 2 +- mcron.texinfo.in | 16 ++++++---------- 9 files changed, 71 insertions(+), 91 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4d2dae2..821f761 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,3 +1,13 @@ +Authors of GNU mcron. + + Copyright (C) 2003, 2005, 2006 Dale Mellor + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. + + + Dale Mellor (dale_mellor@users.sourceforge.net) wrote everything from scratch, with some reference to Paul Vixie's code, with the exceptions noted below. diff --git a/BUGS b/BUGS index a15ecbc..9aaa710 100644 --- a/BUGS +++ b/BUGS @@ -1,5 +1,12 @@ -Copyright (C) 2003 Dale Mellor -*-text-*- -See the end for copying conditions. +GNU mcron --- BUGS -*-text-*- + + Copyright (C) 2003, 2005, 2006 Dale Mellor + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. + + Please send bug reports to bug-mcron@gnu.org. @@ -7,17 +14,3 @@ Please send bug reports to bug-mcron@gnu.org. The currently-known bugs are:- -NONE- - - -_______________________________________________________________________________ -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/ChangeLog b/ChangeLog index 049faf4..4de738f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -134,14 +134,8 @@ ________________________________________________________________________________ -Copyright (C) 2003 Dale Mellor +Copyright (C) 2003, 2005, 2006 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. +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/NEWS b/NEWS index 32599ce..176f29c 100644 --- a/NEWS +++ b/NEWS @@ -1,12 +1,34 @@ Historic moments in the life of mcron. -*-text-*- -Copyright (C) 2003, 2006 Dale Mellor -See the end for copying conditions. + Copyright (C) 2003, 2005, 2006 Dale Mellor + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. + Please send bug reports to bug-mcron@gnu.org. -Thursday, 21st Februrary 2008 +Sunday, 20th June 2010 + + Standardized the copyright notices on all auxiliary files (including this + one!) according to the example set by the GNU hello program. Removed + immutable end texts from the texinfo document. These changes are required + for Debianization. Released as version 1.0.6. + + +Sunday, 13th June 2010 + + Made some technical changes to the build system to aid Debianization. + Released without announcement as version 1.0.5. + + The GIT repository has been completely re-hashed, and now represents a + complete and faithful history of the package's development since its + inception. + + +Thursday, 21st February 2008 The source code is now held in a GIT repository, at git://git.savannah.gnu.org/mcron.git. @@ -75,18 +97,3 @@ Friday, 4th July 2003 We have been accepted as a Savannah project. A CVS repository and web home page have been created. We're still waiting for acceptance as a GNU project. - - - -____________________________________________________________________________ -Copyright (C) 2003, 2006 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/README b/README index c44f0c5..0b22c26 100644 --- a/README +++ b/README @@ -1,8 +1,13 @@ -Copyright (C) 2003 Dale Mellor -*-text-*- -See the end for copying conditions. +GNU mcron --- README -*-text-*- + + Copyright (C) 2003, 2005, 2006 Dale Mellor + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. -This is version 1.0.4 of the GNU mcron program. It is designed and written by +This is version 1.0.6 of the GNU mcron program. It is designed and written by Dale Mellor, and 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 @@ -66,19 +71,3 @@ Mcron is free software. See the file COPYING for copying conditions. The mcron development home page is at http://www.gnu.org/software/mcron, and it can be obtained from ftp://ftp.gnu.org/pub/gnu/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. diff --git a/TODO b/TODO index e5c0c60..e8593aa 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,10 @@ -Copyright (C) 2003 Dale Mellor -*-text-*- -See the end for copying conditions. +GNU mcron --- TODO -*-text-*- + + Copyright (C) 2003, 2005, 2006 Dale Mellor + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. @@ -41,17 +46,3 @@ May happen if version 2.0 ever materializes... crontab-like CGI personality. * 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 191729a..98ebfca 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ AC_PREREQ(2.61) -AC_INIT([mcron], [1.0.5], [dale_mellor@users.sourceforge.net]) +AC_INIT([mcron], [1.0.6], [dale_mellor@users.sourceforge.net]) AM_INIT_AUTOMAKE diff --git a/mcron.1 b/mcron.1 index dacebc4..b936679 100644 --- a/mcron.1 +++ b/mcron.1 @@ -30,7 +30,7 @@ Written by Dale Mellor .SH "REPORTING BUGS" Report bugs to dale_mellor@users.sourceforge.net. .PP -mcron (mcron 1.0.5) +mcron (mcron 1.0.6) .SH COPYRIGHT Copyright \(co 2003, 2006 Dale Mellor .br diff --git a/mcron.texinfo.in b/mcron.texinfo.in index 9bc4084..9fe1d05 100644 --- a/mcron.texinfo.in +++ b/mcron.texinfo.in @@ -12,16 +12,12 @@ program for running jobs at scheduled times. Copyright @copyright{} 2003, 2005, 2006 Dale Mellor @quotation -Permission is granted to copy, distribute and/or modify this document -under the terms of the GNU Free Documentation License, Version 1.1 or -any later version published by the Free Software Foundation; with no -Invariant Sections, with the Front-Cover Texts being ``A GNU Manual,'' -and with the Back-Cover Texts as in (a) below. A copy of the -license is included in the section entitled ``GNU Free Documentation -License.'' - -(a) The FSF's Back-Cover Text is: ``You have freedom to copy and modify -this GNU Manual, like GNU software.'' +Permission is granted to copy, distribute and/or modify this +document under the terms of the GNU Free Documentation License, +Version 1.3 or any later version published by the Free Software +Foundation; with no Invariant Sections, no Front-Cover Texts and +no Back-Cover Texts. A copy of the license is included in the +section entitled ``GNU Free Documentation License''. @end quotation @end copying From bd5a58ac2fc1fa435a499c0dd8e6f779e68551c0 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Sat, 4 Feb 2012 14:33:02 +0000 Subject: [PATCH 027/239] Look for user configuration files in $XDG_CONFIG_HOME (default to ~/.config/cron) as well as ~/.cron. --- ChangeLog | 9 ++++++++ NEWS | 7 ++++++ README | 4 ++-- README--git | 23 ++++++++++++++++++++ configure.ac | 4 ++-- main.scm | 56 ++++++++++++++++++++++++++++-------------------- makefile.am | 3 +++ mcron.1 | 14 ++++++------ mcron.texinfo.in | 53 ++++++++++++++++++++++++--------------------- 9 files changed, 115 insertions(+), 58 deletions(-) create mode 100644 README--git diff --git a/ChangeLog b/ChangeLog index 4de738f..3978ec4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2012-02-04 Dale Mellor + + * main.scm: added search for initial files in + $XDG_CONFIG_HOME/cron directory, defaulting to ~/.config/cron if + the environment variable is not set) as well as in ~/.cron + directory (this is in line with the current FreeDesktop.org + standards). + + 2010-06-13 Dale Mellor * configure.ac: added --enable-no-vixie-clobber argument to diff --git a/NEWS b/NEWS index 176f29c..e53ae23 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,13 @@ Historic moments in the life of mcron. -*-text-*- Please send bug reports to bug-mcron@gnu.org. +Saturday, 4th February 2012 + + Received a suggestion from Antono Vasiljev to look in FreeDesktop.org's + standard user configuration directories for user script files. This is + implemented in the GIT repository. + + Sunday, 20th June 2010 Standardized the copyright notices on all auxiliary files (including this diff --git a/README b/README index 0b22c26..d4f7b6a 100644 --- a/README +++ b/README @@ -1,13 +1,13 @@ GNU mcron --- README -*-text-*- - Copyright (C) 2003, 2005, 2006 Dale Mellor + Copyright (C) 2003, 2005, 2006, 2012 Dale Mellor Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. -This is version 1.0.6 of the GNU mcron program. It is designed and written by +This is version 1.0.7 of the GNU mcron program. It is designed and written by Dale Mellor, and 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 diff --git a/README--git b/README--git new file mode 100644 index 0000000..14d5717 --- /dev/null +++ b/README--git @@ -0,0 +1,23 @@ +GNU mcron --- README--git -*-text-*- + + Copyright (C) 2012 Dale Mellor + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. + + +If you have pulled mcron from the GIT repository, these are the steps you will +need to take to build it the first time: + +1) cp mcron.texinfo.in mcron.texinfo +2) aclocal +4) autoconf +3) automake -a +5) rm mcron.texinfo +6) ./configure --prefix={wherever} +7) make install + + +After that it should just be a simple matter of typing `make install' when you +want to build a version with changes in it. diff --git a/configure.ac b/configure.ac index 98ebfca..6be28a4 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. -# Copyright (C) 2003, 2005 Dale Mellor +# Copyright (C) 2003, 2005, 2012 Dale Mellor # # This file is part of GNU mcron. # @@ -21,7 +21,7 @@ AC_PREREQ(2.61) -AC_INIT([mcron], [1.0.6], [dale_mellor@users.sourceforge.net]) +AC_INIT([mcron], [1.0.7], [dale_mellor@users.sourceforge.net]) AM_INIT_AUTOMAKE diff --git a/main.scm b/main.scm index 5470a55..2c6738e 100644 --- a/main.scm +++ b/main.scm @@ -1,4 +1,4 @@ -;; Copyright (C) 2003 Dale Mellor +;; Copyright (C) 2003, 2012 Dale Mellor ;; ;; This file is part of GNU mcron. ;; @@ -150,14 +150,14 @@ Usage: " (car (command-line)) ((mcron) " [OPTIONS] [FILES]\n Run an mcron process according to the specifications in the FILES (`-' for\n -standard input), or use all the files in ~/.cron with .guile or .vixie\n -extensions.\n +standard input), or use all the files in ~/.config/cron (or the \n +deprecated ~/.cron) with .guile or .vixie extensions.\n \n -v, --version Display version\n -h, --help Display this help message\n -sN, --schedule[=]N Display the next N jobs that will be run by mcron\n - -d, --daemon Immediately detach the program from the terminal and\n - run as a daemon process\n + -d, --daemon Immediately detach the program from the terminal\n + and run as a daemon process\n -i, --stdin=(guile|vixie) Format of data passed as standard input or\n file arguments (default guile)") @@ -296,22 +296,32 @@ Report bugs to " config-package-bugreport ".\n -;; Procedure to run through all the files in a user's ~/.cron directory (only -;; happens under the mcron personality). +;; Procedure to run through all the files in a user's ~/.cron and/or +;; $XDG_CONFIG_HOME/cron or ~/.config/cron directories (only happens under the +;; mcron personality). (define (process-files-in-user-directory) - (catch #t (lambda () - (let* ((dir-path (string-append (passwd:dir (getpw (getuid))) - "/.cron")) - (directory (opendir dir-path))) - (do ((file-name (readdir directory) (readdir directory))) - ((eof-object? file-name) (closedir directory)) - (process-user-file (string-append dir-path - "/" - file-name))))) - (lambda (key . args) - (mcron-error 13 "Cannot read files in your ~/.cron directory.")))) - + (let ((errors 0) + (home-directory (passwd:dir (getpw (getuid))))) + (map (lambda (config-directory) + (catch #t + (lambda () + (let ((directory (opendir config-directory))) + (do ((file-name (readdir directory) (readdir directory))) + ((eof-object? file-name) (closedir directory)) + (process-user-file (string-append config-directory + "/" + file-name))))) + (lambda (key . args) + (set! errors (1+ errors))))) + (list (string-append home-directory "/.cron") + (string-append (or (getenv "XDG_CONFIG_HOME") + (string-append home-directory "/.config")) + "/cron"))) + (if (eq? 2 errors) + (mcron-error 13 + "Cannot read files in your ~/.config/cron (or ~/.cron) " + "directory.")))) @@ -361,9 +371,9 @@ Report bugs to " config-package-bugreport ".\n ;; 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 -;; passed on the command line, or else all the ones in the user's .cron -;; directory. If we are running under the cron personality, we read the -;; /var/cron/tabs directory and also the /etc/crontab file. +;; passed on the command line, or else all the ones in the user's .config/cron +;; (or .cron) directory. If we are running under the cron personality, we read +;; the /var/cron/tabs directory and also the /etc/crontab file. (case command-type ((mcron) (if (null? (option-ref options '() '())) @@ -380,7 +390,7 @@ Report bugs to " config-package-bugreport ".\n (if (not (option-ref options 'noetc #f)) (begin (display - "WARNING: cron will check for updates to /etc/crontab EVERY MINUTE. If you do\n +"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") diff --git a/makefile.am b/makefile.am index 4474ffe..9d19014 100644 --- a/makefile.am +++ b/makefile.am @@ -49,6 +49,9 @@ pkgdata_DATA = core.scm environment.scm job-specifier.scm redirect.scm \ # like core.*, so we have to keep re-making it (I lost a good day's work because # of this). +mcron : mcron.c + $(CC) $(AM_CFLAGS) mcron.c -o mcron $(AM_LDFLAGS) + core.scm : mcron-core.scm $(CP) mcron-core.scm core.scm diff --git a/mcron.1 b/mcron.1 index b936679..ad0f7fc 100644 --- a/mcron.1 +++ b/mcron.1 @@ -1,5 +1,5 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. -.TH MCRON "1" "June 2010" "mcron " "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.4. +.TH MCRON "1" "February 2012" "mcron " "User Commands" .SH NAME mcron \- a program to run tasks at regular (or not) intervals .SH SYNOPSIS @@ -7,8 +7,8 @@ mcron \- a program to run tasks at regular (or not) intervals [\fIOPTIONS\fR] [\fIFILES\fR] .SH DESCRIPTION Run an mcron process according to the specifications in the FILES (`\-' for -standard input), or use all the files in ~/.cron with .guile or .vixie -extensions. +standard input), or use all the files in ~/.config/cron (or the +deprecated ~/.cron) with .guile or .vixie extensions. .TP \fB\-v\fR, \fB\-\-version\fR Display version @@ -20,8 +20,8 @@ Display this help message Display the next N jobs that will be run by mcron .TP \fB\-d\fR, \fB\-\-daemon\fR -Immediately detach the program from the terminal and -run as a daemon process +Immediately detach the program from the terminal +and run as a daemon process .TP \fB\-i\fR, \fB\-\-stdin=\fR(guile|vixie) Format of data passed as standard input or file arguments (default guile) @@ -30,7 +30,7 @@ Written by Dale Mellor .SH "REPORTING BUGS" Report bugs to dale_mellor@users.sourceforge.net. .PP -mcron (mcron 1.0.6) +mcron (mcron 1.0.7) .SH COPYRIGHT Copyright \(co 2003, 2006 Dale Mellor .br diff --git a/mcron.texinfo.in b/mcron.texinfo.in index 9fe1d05..4f9f855 100644 --- a/mcron.texinfo.in +++ b/mcron.texinfo.in @@ -9,7 +9,7 @@ @copying This manual is for GNU mcron (version @VERSION@), which is a program for running jobs at scheduled times. -Copyright @copyright{} 2003, 2005, 2006 Dale Mellor +Copyright @copyright{} 2003, 2005, 2006, 2012 Dale Mellor @quotation Permission is granted to copy, distribute and/or modify this @@ -192,8 +192,10 @@ how to run mcron to make them happen. @cindex examples, guile @cindex example, run a program every hour You have an executable @code{my-program} in your home directory, which -you want to run every hour. Create a file @code{job.guile} in directory -@code{~/.cron} with the following contents +you want to run every hour. Create a file @code{job.guile} in +directory @code{~/.config/cron} (this path may be altered by the +@code{$XDG_CONFIG_HOME} environment variable) with the following +contents @example (job '(next-hour) "my-program") @@ -224,7 +226,7 @@ also the next section) and run the @code{mcron} command. If you want to run other jobs, you can either add more lines to this -file, or you can create other files in your @code{.cron} directory +file, or you can create other files in your @code{.config/cron} directory with the @code{.guile} extension. Alternatively, you can use any file you want and pass it as an argument to @code{mcron}, or even pipe the commands into the standard input. @@ -808,26 +810,28 @@ place in the part which implements the mcron personality. @cindex mcron arguments @cindex command line, mcron @cindex mcron command line -Mcron should be run by the user who wants to schedule his jobs. It may -be made a background job using the facilities of the shell. The basic -command is -@code{mcron [OPTION ...] [file ...]} -which has the effect of reading all the configuration files specified -(subject to the options) and then waiting until it is time to execute -some command. If no files are given on the command line, then mcron -will look in the user's ~/.cron directory. In either case, files which -end in the extension .vixie or .vix will be assumed to contain -Vixie-style crontabs, and files ending .guile or .gle will be assumed -to contain scheme code and will be executed as such; ANY OTHER FILES -WILL BE IGNORED - specify a file name of ``-'' and then pipe the files -into the standard input if you really want to read them, possibly -using the @code{stdin} option to specify the type of file. +Mcron should be run by the user who wants to schedule his jobs. It +may be made a background job using the facilities of the shell. The +basic command is @code{mcron [OPTION ...] [file ...]} which has the +effect of reading all the configuration files specified (subject to +the options) and then waiting until it is time to execute some +command. If no files are given on the command line, then mcron will +look in the user's cron configuration directories: these are ~/.cron +(deprecated), the directory indicated by the @code{XDG_CONFIG_HOME} +environment variable, or ~/.config/cron if this variable is not set. +In any case, files which end in the extension .vixie or .vix will be +assumed to contain Vixie-style crontabs, and files ending .guile or +.gle will be assumed to contain scheme code and will be executed as +such; ANY OTHER FILES WILL BE IGNORED - specify a file name of ``-'' +and then pipe the files into the standard input if you really want to +read them, possibly using the @code{stdin} option to specify the type +of file. The program accepts the following options. @table @option -@item -s [count] -@itemx --schedule[=count] +@item -s count +@itemx --schedule=count @cindex printout of jobs schedule @cindex schedule of jobs, listing @cindex options, schedule @@ -838,8 +842,7 @@ 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. +The count indicates the number of commands to display. @cindex daemon option @cindex options, daemon @@ -1109,8 +1112,10 @@ The last component of the name of the program was not one of @code{mcron}, @code{cron}, @code{crond} or @code{crontab}. @item 13 -Either the ~/.cron directory does not exist, or there is a problem -reading the files there. +Either none of the user's configuration directories exist, or there is a problem +reading the files there. The configuration directories are ~/.cron +and the directory pointed to by the @code{XDG_CONFIG_HOME} environment +variable, or ~/.config/cron if this is not set. @c @item 14 @c There is a problem writing to /var/cron/update. This is probably From c45e7c447bf1d95247225d1c70e0ce593cba2ddf Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Mon, 28 Apr 2014 11:47:55 +0100 Subject: [PATCH 028/239] Now runs (only) against guile-2.0. --- .gitignore | 3 +- ChangeLog | 5 ++ README | 4 +- README--git | 12 ++-- TODO | 4 +- configure.ac | 21 ++----- crontab.scm | 154 +++++++++++++++++++++++++---------------------- main.scm | 2 +- makefile.am | 8 +-- mcron.1 | 50 --------------- mcron.c.template | 10 +-- mcron.texinfo.in | 2 +- 12 files changed, 112 insertions(+), 163 deletions(-) diff --git a/.gitignore b/.gitignore index e760631..f8096eb 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ INSTALL aclocal.m4 autom4te.cache +compile config.log config.scm config.status @@ -15,7 +16,7 @@ makefile.in mcron mcron.c mcron.info -mcron.o +*.o mcron.texinfo missing texinfo.tex diff --git a/ChangeLog b/ChangeLog index 3978ec4..c604b83 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2014-04-28 Dale Mellor + + * We now run against, and require, guile-2.0. + + 2012-02-04 Dale Mellor * main.scm: added search for initial files in diff --git a/README b/README index d4f7b6a..9f4f625 100644 --- a/README +++ b/README @@ -1,13 +1,13 @@ GNU mcron --- README -*-text-*- - Copyright (C) 2003, 2005, 2006, 2012 Dale Mellor + Copyright (C) 2003, 2005, 2006, 2012, 2014 Dale Mellor Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. -This is version 1.0.7 of the GNU mcron program. It is designed and written by +This is version 1.0.8 of the GNU mcron program. It is designed and written by Dale Mellor, and 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 diff --git a/README--git b/README--git index 14d5717..43e9890 100644 --- a/README--git +++ b/README--git @@ -1,6 +1,6 @@ GNU mcron --- README--git -*-text-*- - Copyright (C) 2012 Dale Mellor + Copyright (C) 2012, 2014 Dale Mellor Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright @@ -10,11 +10,11 @@ GNU mcron --- README--git -*-text-*- If you have pulled mcron from the GIT repository, these are the steps you will need to take to build it the first time: -1) cp mcron.texinfo.in mcron.texinfo -2) aclocal -4) autoconf -3) automake -a -5) rm mcron.texinfo +1) aclocal +2) autoconf +3) automake -a (will error) +4) ./configure (will error) +5) automake -a 6) ./configure --prefix={wherever} 7) make install diff --git a/TODO b/TODO index e8593aa..9ed8bca 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,6 @@ GNU mcron --- TODO -*-text-*- - Copyright (C) 2003, 2005, 2006 Dale Mellor + Copyright (C) 2003, 2005, 2006, 2014 Dale Mellor Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright @@ -45,4 +45,4 @@ May happen if version 2.0 ever materializes... * TCP socket to allow control via HTTP (web browser interface). Or maybe crontab-like CGI personality. - * GTK+/Bononbo/Gnome2 interface. + * GTK+/d-bus/Gnome3 interface. diff --git a/configure.ac b/configure.ac index 6be28a4..0ffd581 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. -# Copyright (C) 2003, 2005, 2012 Dale Mellor +# Copyright (C) 2003, 2005, 2012, 2014 Dale Mellor # # This file is part of GNU mcron. # @@ -42,11 +42,9 @@ AC_SUBST(CONFIG_DEBUG) AC_PROG_AWK AC_PROG_EGREP -AC_PROG_CC -GUILE_PROGS -GUILE_FLAGS -GUILE_SITE_DIR +AM_PROG_CC_C_O +PKG_CHECK_MODULES(GUILE, guile-2.0 >= 2.0.7) # Checks for programs. @@ -72,17 +70,6 @@ if test "x$ac_cv_prog_CP" = "x"; then fi -# Check the Guile version. - -AC_MSG_CHECKING(for guile version >= 1.8.0) -if [$GUILE --version | $HEAD -1 | $AWK '{print $2}' | \ - $EGREP -q '^1\.8\.']; then - AC_MSG_RESULT(OK) -else - AC_MSG_ERROR([Sorry, Guile 1.8.0 or greater is needed to run mcron]) -fi - - # Now find a sendmail or equivalent. AC_CHECK_PROGS(SENDMAIL, sendmail) @@ -182,5 +169,5 @@ real_program_prefix=`echo $program_prefix | sed s/NONE//` AC_SUBST(real_program_prefix) -AC_CONFIG_FILES(makefile config.scm mcron.texinfo) +AC_CONFIG_FILES(mcron.texinfo makefile config.scm) AC_OUTPUT diff --git a/crontab.scm b/crontab.scm index ff74947..30e5592 100644 --- a/crontab.scm +++ b/crontab.scm @@ -1,4 +1,4 @@ -;; Copyright (C) 2003 Dale Mellor +;; Copyright (C) 2003, 2014 Dale Mellor ;; ;; This file is part of GNU mcron. ;; @@ -27,14 +27,15 @@ ;; Procedure to communicate with running cron daemon that a user has modified ;; his crontab. The user name is written to the /var/cron/socket UNIX socket. -(define (hit-server user-name) - (catch #t (lambda () - (let ((socket (socket AF_UNIX SOCK_STREAM 0))) - (connect socket AF_UNIX config-socket-file) - (display user-name socket) - (close socket))) - (lambda (key . args) - (display "Warning: a cron daemon is not running.\n")))) +(let ((hit-server + (lambda (user-name) + (catch #t (lambda () + (let ((socket (socket AF_UNIX SOCK_STREAM 0))) + (connect socket AF_UNIX config-socket-file) + (display user-name socket) + (close socket))) + (lambda (key . args) + (display "Warning: a cron daemon is not running.\n"))))) @@ -42,89 +43,95 @@ ;; /var/cron/allow and /var/cron/deny), and determine if the given name is in ;; there. The procedure returns #t, #f, or '() if the file does not exist. -(define (in-access-file? file name) - (catch #t (lambda () - (with-input-from-file file (lambda () - (let loop ((input (read-line))) - (if (eof-object? input) - #f - (if (string=? input name) - #t - (loop (read-line)))))))) - (lambda (key . args) '()))) + (in-access-file? + (lambda (file name) + (catch #t (lambda () + (with-input-from-file + file + (lambda () + (let loop ((input (read-line))) + (if (eof-object? input) + #f + (if (string=? input name) + #t + (loop (read-line)))))))) + (lambda (key . args) '())))) + + + + ;; This program should have been installed SUID root. Here we get the + ;; passwd entry for the real user who is running this program. + + (crontab-real-user (passwd:name (getpw (getuid))))) -;; This program should have been installed SUID root. Here we get the passwd -;; entry for the real user who is running this program. + ;; If the real user is not allowed to use crontab due to the /var/cron/allow + ;; and/or /var/cron/deny files, bomb out now. -(define crontab-real-user (passwd:name (getpw (getuid)))) + (if (or (eq? (in-access-file? config-allow-file crontab-real-user) #f) + (eq? (in-access-file? config-deny-file crontab-real-user) #t)) + (mcron-error 6 "Access denied by system operator.")) + + + + ;; Check that no more than one of the mutually exclusive options are being + ;; used. + + (if (> (+ (if (option-ref options 'edit #f) 1 0) + (if (option-ref options 'list #f) 1 0) + (if (option-ref options 'remove #f) 1 0)) + 1) + (mcron-error 7 "Only one of options -e, -l or -r can be used.")) -;; If the real user is not allowed to use crontab due to the /var/cron/allow -;; and/or /var/cron/deny files, bomb out now. + ;; Check that a non-root user is trying to read someone else's files. -(if (or (eq? (in-access-file? config-allow-file crontab-real-user) #f) - (eq? (in-access-file? config-deny-file crontab-real-user) #t)) - (mcron-error 6 "Access denied by system operator.")) + (if (and (not (eqv? (getuid) 0)) + (option-ref options 'user #f)) + (mcron-error 8 "Only root can use the -u option.")) -;; Check that no more than one of the mutually exclusive options are being used. + (let ( -(if (> (+ (if (option-ref options 'edit #f) 1 0) - (if (option-ref options 'list #f) 1 0) - (if (option-ref options 'remove #f) 1 0)) - 1) - (mcron-error 7 "Only one of options -e, -l or -r can be used.")) + + ;; Iff the --user option is given, the crontab-user may be different + ;; from the real user. + + (crontab-user (option-ref options 'user crontab-real-user)) + + + ;; So now we know which crontab file we will be manipulating. + + (crontab-file (string-append config-spool-dir "/" crontab-user)) -;; Check that a non-root user is trying to read someone else's files. + ;; Display the prompt and wait for user to type his choice. Return #t if + ;; the answer begins with 'y' or 'Y', return #f if it begins with 'n' or + ;; 'N', otherwise ask again. -(if (and (not (eqv? (getuid) 0)) - (option-ref options 'user #f)) - (mcron-error 8 "Only root can use the -u option.")) + (get-yes-no (lambda (prompt . re-prompt) + (if (not (null? re-prompt)) + (display "Please answer y or n.\n")) + (display (string-append prompt " ")) + (let ((r (read-line))) + (if (not (string-null? r)) + (case (string-ref r 0) + ((#\y #\Y) #t) + ((#\n #\N) #f) + (else (get-yes-no prompt #t))) + (get-yes-no prompt #t)))))) -;; Iff the --user option is given, the crontab-user may be different from the -;; real user. + ;; There are four possible sub-personalities to the crontab personality: + ;; list, remove, edit and replace (when the user uses no options but + ;; supplies file names on the command line). -(define crontab-user (option-ref options 'user crontab-real-user)) - - - -;; So now we know which crontab file we will be manipulating. - -(define crontab-file (string-append config-spool-dir "/" crontab-user)) - - - -;; Display the prompt and wait for user to type his choice. Return #t if the -;; answer begins with 'y' or 'Y', return #f if it begins with 'n' or 'N', -;; otherwise ask again. - -(define (get-yes-no prompt . re-prompt) - (if (not (null? re-prompt)) - (display "Please answer y or n.\n")) - (display (string-append prompt " ")) - (let ((r (read-line))) - (if (not (string-null? r)) - (case (string-ref r 0) - ((#\y #\Y) #t) - ((#\n #\N) #f) - (else (get-yes-no prompt #t))) - (get-yes-no prompt #t)))) - - - -;; There are four possible sub-personalities to the crontab personality: list, -;; remove, edit and replace (when the user uses no options but supplies file -;; names on the command line). - -(cond + (cond ;; In the list personality, we simply open the crontab and copy it @@ -216,3 +223,6 @@ (else (mcron-error 15 "usage error: file name must be specified for replace."))) + + +)) ;; End of file-level let-scopes. diff --git a/main.scm b/main.scm index 2c6738e..36adef9 100644 --- a/main.scm +++ b/main.scm @@ -131,7 +131,7 @@ " command-name " (" config-package-string ")\n Written by Dale Mellor\n \n -Copyright (C) 2003, 2006 Dale Mellor\n +Copyright (C) 2003, 2006, 2014 Dale Mellor\n This is free software; see the source for copying conditions. There is NO\n warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n ")) diff --git a/makefile.am b/makefile.am index 9d19014..85610df 100644 --- a/makefile.am +++ b/makefile.am @@ -31,15 +31,14 @@ EXTRA_DIST = makefile.ed main.scm mcron-core.scm vixie-specification.scm \ crontab.scm environment.scm job-specifier.scm redirect.scm \ vixie-time.scm mcron.c.template BUGS -AM_LDFLAGS = @GUILE_LDFLAGS@ -AM_CFLAGS = @GUILE_CFLAGS@ -DGUILE_LOAD_PATH=\"$(datadir)\" - info_TEXINFOS = mcron.texinfo dist_man1_MANS = mcron.1 bin_PROGRAMS = mcron mcron_SOURCES = mcron.c +mcron_LDADD = @GUILE_LIBS@ +mcron_CFLAGS = @GUILE_CFLAGS@ -DGUILE_LOAD_PATH=\"$(datadir)\" pkgdata_DATA = core.scm environment.scm job-specifier.scm redirect.scm \ vixie-time.scm vixie-specification.scm config.scm @@ -49,9 +48,6 @@ pkgdata_DATA = core.scm environment.scm job-specifier.scm redirect.scm \ # like core.*, so we have to keep re-making it (I lost a good day's work because # of this). -mcron : mcron.c - $(CC) $(AM_CFLAGS) mcron.c -o mcron $(AM_LDFLAGS) - core.scm : mcron-core.scm $(CP) mcron-core.scm core.scm diff --git a/mcron.1 b/mcron.1 index ad0f7fc..e69de29 100644 --- a/mcron.1 +++ b/mcron.1 @@ -1,50 +0,0 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.4. -.TH MCRON "1" "February 2012" "mcron " "User Commands" -.SH NAME -mcron \- a program to run tasks at regular (or not) intervals -.SH SYNOPSIS -.B mcron -[\fIOPTIONS\fR] [\fIFILES\fR] -.SH DESCRIPTION -Run an mcron process according to the specifications in the FILES (`\-' for -standard input), or use all the files in ~/.config/cron (or the -deprecated ~/.cron) with .guile or .vixie extensions. -.TP -\fB\-v\fR, \fB\-\-version\fR -Display version -.TP -\fB\-h\fR, \fB\-\-help\fR -Display this help message -.TP -\fB\-sN\fR, \fB\-\-schedule[\fR=\fI]N\fR -Display the next N jobs that will be run by mcron -.TP -\fB\-d\fR, \fB\-\-daemon\fR -Immediately detach the program from the terminal -and run as a daemon process -.TP -\fB\-i\fR, \fB\-\-stdin=\fR(guile|vixie) Format of data passed as standard input or -file arguments (default guile) -.SH AUTHOR -Written by Dale Mellor -.SH "REPORTING BUGS" -Report bugs to dale_mellor@users.sourceforge.net. -.PP -mcron (mcron 1.0.7) -.SH COPYRIGHT -Copyright \(co 2003, 2006 Dale Mellor -.br -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -.SH "SEE ALSO" -The full documentation for -.B mcron -is maintained as a Texinfo manual. If the -.B info -and -.B mcron -programs are properly installed at your site, the command -.IP -.B info mcron -.PP -should give you access to the complete manual. diff --git a/mcron.c.template b/mcron.c.template index cba503e..e9a755d 100644 --- a/mcron.c.template +++ b/mcron.c.template @@ -1,6 +1,6 @@ /* -*-c-*- */ /* - * Copyright (C) 2003 Dale Mellor + * Copyright (C) 2003, 2014 Dale Mellor * * This file is part of GNU mcron. * @@ -66,7 +66,7 @@ void react_to_terminal_signal (int sig) { - scm_eval_string (scm_take0str ("(delete-run-file)") ); + scm_c_eval_string ("(delete-run-file)"); exit (1); } @@ -100,9 +100,9 @@ inner_main () { scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); - scm_eval_string (scm_take0str ( - GUILE_PROGRAM_GOES_HERE - ) ); + scm_c_eval_string ( + GUILE_PROGRAM_GOES_HERE + ); } diff --git a/mcron.texinfo.in b/mcron.texinfo.in index 4f9f855..bbf8e5b 100644 --- a/mcron.texinfo.in +++ b/mcron.texinfo.in @@ -9,7 +9,7 @@ @copying This manual is for GNU mcron (version @VERSION@), which is a program for running jobs at scheduled times. -Copyright @copyright{} 2003, 2005, 2006, 2012 Dale Mellor +Copyright @copyright{} 2003, 2005, 2006, 2012, 2014 Dale Mellor @quotation Permission is granted to copy, distribute and/or modify this From c0ba5c6036e8962c3671928c54a2d66a4c805435 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Sun, 25 May 2014 14:57:37 +0100 Subject: [PATCH 029/239] Juggled build infrastructure to make mcron.1 man page properly. --- ChangeLog | 12 ++++++- configure.ac | 8 +++-- makefile.am | 35 +++++++------------ makefile.ed | 4 +-- mcron.1 | 0 config.scm.in => scm/mcron/config.scm.in | 0 crontab.scm => scm/mcron/crontab.scm | 0 environment.scm => scm/mcron/environment.scm | 0 .../mcron/job-specifier.scm | 0 main.scm => scm/mcron/main.scm | 0 mcron-core.scm => scm/mcron/mcron-core.scm | 0 redirect.scm => scm/mcron/redirect.scm | 0 .../mcron/vixie-specification.scm | 0 vixie-time.scm => scm/mcron/vixie-time.scm | 0 14 files changed, 30 insertions(+), 29 deletions(-) delete mode 100644 mcron.1 rename config.scm.in => scm/mcron/config.scm.in (100%) rename crontab.scm => scm/mcron/crontab.scm (100%) rename environment.scm => scm/mcron/environment.scm (100%) rename job-specifier.scm => scm/mcron/job-specifier.scm (100%) rename main.scm => scm/mcron/main.scm (100%) rename mcron-core.scm => scm/mcron/mcron-core.scm (100%) rename redirect.scm => scm/mcron/redirect.scm (100%) rename vixie-specification.scm => scm/mcron/vixie-specification.scm (100%) rename vixie-time.scm => scm/mcron/vixie-time.scm (100%) diff --git a/ChangeLog b/ChangeLog index c604b83..15e01c0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,17 @@ +2014-05-25 Dale Mellor + + * Juggled build infrastructure so that we can make the minimal man + page in the proper autotools way. + + * configure.ac: version to 1.0.8. + + 2014-04-28 Dale Mellor * We now run against, and require, guile-2.0. + * configure.ac: version to 1.0.7. + 2012-02-04 Dale Mellor @@ -148,7 +158,7 @@ ________________________________________________________________________________ -Copyright (C) 2003, 2005, 2006 Dale Mellor +Copyright (C) 2003, 2005, 2006, 2014 Dale Mellor Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright diff --git a/configure.ac b/configure.ac index 0ffd581..c819d4d 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ AC_PREREQ(2.61) -AC_INIT([mcron], [1.0.7], [dale_mellor@users.sourceforge.net]) +AC_INIT([mcron], [1.0.8], [dale_mellor@users.sourceforge.net]) AM_INIT_AUTOMAKE @@ -44,10 +44,12 @@ AC_PROG_AWK AC_PROG_EGREP AM_PROG_CC_C_O -PKG_CHECK_MODULES(GUILE, guile-2.0 >= 2.0.7) +PKG_CHECK_MODULES(GUILE, guile-2.0) # Checks for programs. +AM_MISSING_PROG(HELP2MAN, help2man, $missing_dir) + AC_CHECK_PROGS(SED, sed) if test "x$ac_cv_prog_SED" = "x"; then AC_MSG_ERROR(sed not found) @@ -169,5 +171,5 @@ real_program_prefix=`echo $program_prefix | sed s/NONE//` AC_SUBST(real_program_prefix) -AC_CONFIG_FILES(mcron.texinfo makefile config.scm) +AC_CONFIG_FILES(mcron.texinfo makefile scm/mcron/makefile scm/mcron/config.scm) AC_OUTPUT diff --git a/makefile.am b/makefile.am index 85610df..a7f0e75 100644 --- a/makefile.am +++ b/makefile.am @@ -18,40 +18,33 @@ ## Process this file with automake to produce Makefile.in +SUBDIRS = scm/mcron . + ED = @ED@ # !!!! Are these needed? CP = @CP@ MAINTAINERCLEANFILES = configure makefile makefile.in config.guess config.sub \ install-sh missing texinfo.tex INSTALL \ - aclocal.m4 compile depcomp + aclocal.m4 compile depcomp mcron.1 CLEANFILES = mcron.c core.scm -EXTRA_DIST = makefile.ed main.scm mcron-core.scm vixie-specification.scm \ - crontab.scm environment.scm job-specifier.scm redirect.scm \ - vixie-time.scm mcron.c.template BUGS +EXTRA_DIST = makefile.ed mcron.c.template BUGS info_TEXINFOS = mcron.texinfo -dist_man1_MANS = mcron.1 +man_MANS = mcron.1 bin_PROGRAMS = mcron mcron_SOURCES = mcron.c mcron_LDADD = @GUILE_LIBS@ -mcron_CFLAGS = @GUILE_CFLAGS@ -DGUILE_LOAD_PATH=\"$(datadir)\" -pkgdata_DATA = core.scm environment.scm job-specifier.scm redirect.scm \ - vixie-time.scm vixie-specification.scm config.scm +# The second option is so that we can execute the binary in the local directory, +# in turn so that we can do mcron --help during the build process. +mcron_CFLAGS = @GUILE_CFLAGS@ -DGUILE_LOAD_PATH=\"$(datadir):./scm:...\" -# If you're wondering, the configure script keeps deleting all files with a name -# like core.*, so we have to keep re-making it (I lost a good day's work because -# of this). - -core.scm : mcron-core.scm - $(CP) mcron-core.scm core.scm - -mcron.c : main.scm crontab.scm makefile.ed mcron.c.template +mcron.c : scm/mcron/main.scm scm/mcron/crontab.scm makefile.ed mcron.c.template @echo 'Building mcron.c...' @$(ED) < makefile.ed > /dev/null 2>&1 @rm -f mcron.escaped.scm > /dev/null 2>&1 @@ -76,9 +69,6 @@ install-exec-hook: else \ echo "+++ WARNING: NON-ROOT INSTALL: ONLY mcron WILL BE INSTALLED, NOT ANY OF THE VIXIE REPLACEMENT PROGRAMS"; \ fi - @echo - @echo " AFTER INSTALLATION, CONSIDER RUNNING make cook-up-man" - @echo uninstall-hook: @@ -89,7 +79,6 @@ uninstall-hook: # Not part of formal package building, but a rule for manual use to get the # elemental man page. Will only work once the mcron program is installed. -cook-up-man: - help2man -n 'a program to run tasks at regular (or not) intervals' \ - $(fpp)mcron > mcron.1 - $(MAKE) install +mcron.1 : mcron.c + $(HELP2MAN) -n 'a program to run tasks at regular (or not) intervals' \ + ./mcron > mcron.1 diff --git a/makefile.ed b/makefile.ed index 5c89344..7047ec7 100644 --- a/makefile.ed +++ b/makefile.ed @@ -17,9 +17,9 @@ # # # -e main.scm +e scm/mcron/main.scm /\(load "crontab.scm"\)/d --1r crontab.scm +-1r scm/mcron/crontab.scm %s/\\/\\\\/g %s/"/\\"/g %s/ *;;.*$/ /g diff --git a/mcron.1 b/mcron.1 deleted file mode 100644 index e69de29..0000000 diff --git a/config.scm.in b/scm/mcron/config.scm.in similarity index 100% rename from config.scm.in rename to scm/mcron/config.scm.in diff --git a/crontab.scm b/scm/mcron/crontab.scm similarity index 100% rename from crontab.scm rename to scm/mcron/crontab.scm diff --git a/environment.scm b/scm/mcron/environment.scm similarity index 100% rename from environment.scm rename to scm/mcron/environment.scm diff --git a/job-specifier.scm b/scm/mcron/job-specifier.scm similarity index 100% rename from job-specifier.scm rename to scm/mcron/job-specifier.scm diff --git a/main.scm b/scm/mcron/main.scm similarity index 100% rename from main.scm rename to scm/mcron/main.scm diff --git a/mcron-core.scm b/scm/mcron/mcron-core.scm similarity index 100% rename from mcron-core.scm rename to scm/mcron/mcron-core.scm diff --git a/redirect.scm b/scm/mcron/redirect.scm similarity index 100% rename from redirect.scm rename to scm/mcron/redirect.scm diff --git a/vixie-specification.scm b/scm/mcron/vixie-specification.scm similarity index 100% rename from vixie-specification.scm rename to scm/mcron/vixie-specification.scm diff --git a/vixie-time.scm b/scm/mcron/vixie-time.scm similarity index 100% rename from vixie-time.scm rename to scm/mcron/vixie-time.scm From d69a2b91ac8c777d9239416d26a5c77f980bc9b6 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Sun, 25 May 2014 15:08:45 +0100 Subject: [PATCH 030/239] Distribute the minimal man page in case the builder hasn't get help2man. --- makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile.am b/makefile.am index a7f0e75..1b27e7a 100644 --- a/makefile.am +++ b/makefile.am @@ -33,7 +33,7 @@ EXTRA_DIST = makefile.ed mcron.c.template BUGS info_TEXINFOS = mcron.texinfo -man_MANS = mcron.1 +dist_man_MANS = mcron.1 bin_PROGRAMS = mcron mcron_SOURCES = mcron.c From 998f7eeaefa4280aad5d82f37f7bac30229bba40 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Sun, 25 May 2014 17:18:04 +0100 Subject: [PATCH 031/239] Correction in 'make clean' rules. --- makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile.am b/makefile.am index 1b27e7a..633cf2f 100644 --- a/makefile.am +++ b/makefile.am @@ -27,7 +27,7 @@ MAINTAINERCLEANFILES = configure makefile makefile.in config.guess config.sub \ install-sh missing texinfo.tex INSTALL \ aclocal.m4 compile depcomp mcron.1 -CLEANFILES = mcron.c core.scm +CLEANFILES = mcron.c EXTRA_DIST = makefile.ed mcron.c.template BUGS From bc38f2add23919573438b4642fb143428ce05927 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Sun, 25 May 2014 17:21:00 +0100 Subject: [PATCH 032/239] Add maintainer-mode option to configure, to pacify Debian. --- configure.ac | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure.ac b/configure.ac index c819d4d..764ea03 100644 --- a/configure.ac +++ b/configure.ac @@ -40,6 +40,10 @@ fi AC_SUBST(CONFIG_DEBUG) +# We have no interest (hence a no-op), but Debian wants this. +AC_ARG_ENABLE(maintainer-mode) + + AC_PROG_AWK AC_PROG_EGREP AM_PROG_CC_C_O From 2039060a1de3cca3aa3e9a1035ce08b430ff5ea6 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Fri, 26 Jun 2015 19:30:24 +0200 Subject: [PATCH 033/239] Add missing 'makefile.am'. --- .gitignore | 2 +- ChangeLog | 7 +++++++ scm/mcron/makefile.am | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 scm/mcron/makefile.am diff --git a/.gitignore b/.gitignore index f8096eb..00fa239 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,7 @@ depcomp install-sh makefile makefile.in -mcron +/mcron mcron.c mcron.info *.o diff --git a/ChangeLog b/ChangeLog index 15e01c0..cccecbe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2015-06-26 Mathieu Lirzin + + Add missing 'makefile.am'. + * scm/mcron/makefile.am: New file. + * .gitignore: Ignore 'mcron' only in the top-level directory. + + 2014-05-25 Dale Mellor * Juggled build infrastructure so that we can make the minimal man diff --git a/scm/mcron/makefile.am b/scm/mcron/makefile.am new file mode 100644 index 0000000..931b03b --- /dev/null +++ b/scm/mcron/makefile.am @@ -0,0 +1,15 @@ +EXTRA_DIST = main.scm mcron-core.scm vixie-specification.scm \ + crontab.scm environment.scm job-specifier.scm redirect.scm \ + vixie-time.scm + +pkgdata_DATA = core.scm environment.scm job-specifier.scm redirect.scm \ + vixie-time.scm vixie-specification.scm config.scm + + +# If you're wondering, the configure script keeps deleting all files with a name +# like core.*, so we have to keep re-making it (I lost a good day's work because +# of this). + +core.scm : mcron-core.scm + $(CP) mcron-core.scm core.scm + From e6a94adeb3384cb883f49ec5a4cc589df6b40d10 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Fri, 26 Jun 2015 23:17:01 +0200 Subject: [PATCH 034/239] Fix build of the manual. --- .gitignore | 9 ++- ChangeLog | 9 +++ README--git | 11 ++-- configure.ac | 7 +- doc/config.texi.in | 5 ++ mcron.texinfo.in => doc/mcron.texi | 102 +++++++++++++++-------------- makefile.am | 9 +-- 7 files changed, 87 insertions(+), 65 deletions(-) create mode 100644 doc/config.texi.in rename mcron.texinfo.in => doc/mcron.texi (95%) diff --git a/.gitignore b/.gitignore index 00fa239..2bedd6e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,13 +10,18 @@ config.status configure core.scm depcomp +/doc/.dirstamp +/doc/config.texi +/doc/mcron.info +/doc/mcron.1 +/doc/stamp-vti +/doc/version.texi install-sh makefile makefile.in /mcron mcron.c -mcron.info +/mdate-sh *.o -mcron.texinfo missing texinfo.tex diff --git a/ChangeLog b/ChangeLog index cccecbe..806a03f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2015-06-26 Mathieu Lirzin + Fix build of the manual. + * mcron.texinfo.in: Move to ... + * doc/mcron.texi: ... Here. New file. + * doc/config.texi.in: New file. + * configure.ac: Adapt to it. + * makefile.am: Likewise. + * .gitignore: Likewise. + * README--git: Likewise. + Add missing 'makefile.am'. * scm/mcron/makefile.am: New file. * .gitignore: Ignore 'mcron' only in the top-level directory. diff --git a/README--git b/README--git index 43e9890..9ebaa0d 100644 --- a/README--git +++ b/README--git @@ -1,6 +1,7 @@ GNU mcron --- README--git -*-text-*- Copyright (C) 2012, 2014 Dale Mellor + Copyright (C) 2015 Mathieu Lirzin Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright @@ -10,13 +11,9 @@ GNU mcron --- README--git -*-text-*- If you have pulled mcron from the GIT repository, these are the steps you will need to take to build it the first time: -1) aclocal -2) autoconf -3) automake -a (will error) -4) ./configure (will error) -5) automake -a -6) ./configure --prefix={wherever} -7) make install +1) autoreconf -vfi +2) ./configure --prefix={wherever} +3) make install After that it should just be a simple matter of typing `make install' when you diff --git a/configure.ac b/configure.ac index 764ea03..b4ec9f6 100644 --- a/configure.ac +++ b/configure.ac @@ -3,6 +3,7 @@ # Copyright (C) 2003, 2005, 2012, 2014 Dale Mellor +# Copyright (C) 2015 Mathieu Lirzin # # This file is part of GNU mcron. # @@ -174,6 +175,8 @@ AC_SUBST(CONFIG_TMP_DIR) real_program_prefix=`echo $program_prefix | sed s/NONE//` AC_SUBST(real_program_prefix) - -AC_CONFIG_FILES(mcron.texinfo makefile scm/mcron/makefile scm/mcron/config.scm) +AC_CONFIG_FILES([doc/config.texi + makefile + scm/mcron/makefile + scm/mcron/config.scm]) AC_OUTPUT diff --git a/doc/config.texi.in b/doc/config.texi.in new file mode 100644 index 0000000..50d9a18 --- /dev/null +++ b/doc/config.texi.in @@ -0,0 +1,5 @@ +@set CONFIG_SOCKET_FILE @CONFIG_SOCKET_FILE@ +@set CONFIG_SPOOL_DIR @CONFIG_SPOOL_DIR@ +@set CONFIG_PID_FILE @CONFIG_PID_FILE@ +@set CONFIG_ALLOW_FILE @CONFIG_ALLOW_FILE@ +@set CONFIG_DENY_FILE @CONFIG_DENY_FILE@ diff --git a/mcron.texinfo.in b/doc/mcron.texi similarity index 95% rename from mcron.texinfo.in rename to doc/mcron.texi index bbf8e5b..cb97a06 100644 --- a/mcron.texinfo.in +++ b/doc/mcron.texi @@ -1,12 +1,14 @@ \input texinfo @c %**start of header @setfilename mcron.info -@settitle mcron @VERSION@ +@include config.texi +@include version.texi +@settitle mcron @value{VERSION} @c %**end of header @syncodeindex fn cp -@copying This manual is for GNU mcron (version @VERSION@), which is a +@copying This manual is for GNU mcron (version @value{VERSION}), which is a program for running jobs at scheduled times. Copyright @copyright{} 2003, 2005, 2006, 2012, 2014 Dale Mellor @@ -68,36 +70,36 @@ running jobs at scheduled times. Simple examples -* Guile Simple Examples:: -* Vixie Simple Examples:: +* Guile Simple Examples:: +* Vixie Simple Examples:: Full available syntax -* Guile Syntax:: -* Extended Guile examples:: -* Vixie Syntax:: +* Guile Syntax:: +* Extended Guile examples:: +* Vixie Syntax:: Extended Guile examples -* AT commands:: -* Every second Sunday:: -* Two hours every day:: -* Missing the first appointment:: -* Penultimate day of every month:: +* AT commands:: +* Every second Sunday:: +* Two hours every day:: +* Missing the first appointment:: +* Penultimate day of every month:: Vixie -* Paul Vixie's copyright:: -* Crontab file:: -* Incompatibilities with old Unices:: +* Paul Vixie's copyright:: +* Crontab file:: +* Incompatibilities with old Unices:: Detailed invoking -* Invoking mcron:: -* Invoking cron or crond:: +* Invoking mcron:: +* Invoking cron or crond:: * Invoking crontab:: * Behaviour on laptops:: -* Exit codes:: +* Exit codes:: Guile modules @@ -182,8 +184,8 @@ been to allow such simple specifications to be made easily. The examples show how to create the command descriptions, and subsequently how to run mcron to make them happen. @menu -* Guile Simple Examples:: -* Vixie Simple Examples:: +* Guile Simple Examples:: +* Vixie Simple Examples:: @end menu @node Guile Simple Examples, Vixie Simple Examples, Simple examples, Simple examples @@ -258,9 +260,9 @@ on your system, as root. @node Syntax, Invoking, Simple examples, Top @chapter Full available syntax @menu -* Guile Syntax:: -* Extended Guile examples:: -* Vixie Syntax:: +* Guile Syntax:: +* Extended Guile examples:: +* Vixie Syntax:: @end menu @node Guile Syntax, Extended Guile examples, Syntax, Syntax @section Guile Syntax @@ -392,11 +394,11 @@ they seem. The following examples illustrate some pitfalls, and demonstrate how to code around them. @menu -* AT commands:: -* Every second Sunday:: -* Two hours every day:: -* Missing the first appointment:: -* Penultimate day of every month:: +* AT commands:: +* Every second Sunday:: +* Two hours every day:: +* Missing the first appointment:: +* Penultimate day of every month:: @end menu @node AT commands, Every second Sunday, Extended Guile examples, Extended Guile examples @@ -545,9 +547,9 @@ the variable and runs the command in the user's default shell, as advertised by the /etc/passwd file. @menu -* Paul Vixie's copyright:: -* Crontab file:: -* Incompatibilities with old Unices:: +* Paul Vixie's copyright:: +* Crontab file:: +* Incompatibilities with old Unices:: @end menu @@ -796,11 +798,11 @@ place in the part which implements the mcron personality. @menu -* Invoking mcron:: -* Invoking cron or crond:: +* Invoking mcron:: +* Invoking cron or crond:: * Invoking crontab:: * Behaviour on laptops:: -* Exit codes:: +* Exit codes:: @end menu @node Invoking mcron, Invoking cron or crond, Invoking, Invoking @@ -893,21 +895,21 @@ standard output. @cindex invoking cron @cindex crond, invokation @cindex invoking crond -@cindex @CONFIG_SPOOL_DIR@ -@cindex @CONFIG_SOCKET_FILE@ +@cindex @value{CONFIG_SPOOL_DIR} +@cindex @value{CONFIG_SOCKET_FILE} NOTE THAT THIS SECTION ONLY APPLIES IF THE @code{cron} or @code{crond}, and @code{crontab} PROGRAMS HAVE BEEN INSTALLED BY THE SYSTEM ADMINISTRATOR. If the program runs by the name of @code{cron} or @code{crond}, then -it will read all the files in @code{@CONFIG_SPOOL_DIR@} (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 +it will read all the files in @code{@value{CONFIG_SPOOL_DIR}} (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{@CONFIG_SOCKET_FILE@}, 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. +@code{@value{CONFIG_SOCKET_FILE}}, 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 @@ -1060,7 +1062,7 @@ No problems. @item 1 An attempt has been made to start cron but there is already a -@CONFIG_PID_FILE@ file. If there really is no other cron daemon +@value{CONFIG_PID_FILE} file. If there really is no other cron daemon running (this does not include invokations of mcron) then you should remove this file before attempting to run cron. @@ -1078,9 +1080,9 @@ to be specified in one of these forms. @item 4 An attempt to run cron has been made by a user who does not have -permission to access the crontabs in @CONFIG_SPOOL_DIR@. These files -should be readable only by root, and the cron daemon must be run as -root. +permission to access the crontabs in @value{CONFIG_SPOOL_DIR}. These +files should be readable only by root, and the cron daemon must be run +as root. @item 5 An attempt to run mcron has been made, but there are no jobs to @@ -1088,7 +1090,7 @@ schedule! @item 6 The system administrator has blocked this user from using crontab with -the files @CONFIG_ALLOW_FILE@ and @CONFIG_DENY_FILE@. +the files @value{CONFIG_ALLOW_FILE} and @value{CONFIG_DENY_FILE}. @item 7 Crontab has been run with more than one of the arguments @code{-l}, @@ -1248,7 +1250,7 @@ This module is introduced to a program with the command @code{(use-modules (mcron redirect))}. This module provides the @code{with-mail-out} function, described -fully in @ref{Guile Syntax}. +fully in @ref{Guile Syntax}. @node The vixie-time module, The job-specifier module, The redirect module, Guile modules @section The vixie-time module @@ -1325,7 +1327,7 @@ return silently. Otherwise, the behaviour is identical to Once this module has been declared in a program, a crontab file can be used to augment the current job list with a call to -@code{read-vixie-file}. +@code{read-vixie-file}. @node Index, , Guile modules, Top @unnumbered Index diff --git a/makefile.am b/makefile.am index 633cf2f..2229893 100644 --- a/makefile.am +++ b/makefile.am @@ -1,5 +1,6 @@ ## Makefile for the toplevel directory of mcron. ## Copyright (C) 2003 Dale Mellor +## Copyright (C) 2015 Mathieu Lirzin ## # This file is part of GNU mcron. # @@ -31,9 +32,9 @@ CLEANFILES = mcron.c EXTRA_DIST = makefile.ed mcron.c.template BUGS -info_TEXINFOS = mcron.texinfo +info_TEXINFOS = doc/mcron.texi -dist_man_MANS = mcron.1 +dist_man_MANS = doc/mcron.1 bin_PROGRAMS = mcron mcron_SOURCES = mcron.c @@ -79,6 +80,6 @@ uninstall-hook: # Not part of formal package building, but a rule for manual use to get the # elemental man page. Will only work once the mcron program is installed. -mcron.1 : mcron.c +$(dist_man_MANS): mcron.c $(HELP2MAN) -n 'a program to run tasks at regular (or not) intervals' \ - ./mcron > mcron.1 + ./mcron > $@ From eca341bd824c5cfe39fb0001014e5b86933719d9 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Sun, 5 Jul 2015 08:59:31 +0100 Subject: [PATCH 035/239] Remove derived doc/mcron.1 with maintainer-clean. --- makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile.am b/makefile.am index 2229893..65b10d8 100644 --- a/makefile.am +++ b/makefile.am @@ -26,7 +26,7 @@ CP = @CP@ MAINTAINERCLEANFILES = configure makefile makefile.in config.guess config.sub \ install-sh missing texinfo.tex INSTALL \ - aclocal.m4 compile depcomp mcron.1 + aclocal.m4 compile depcomp doc/mcron.1 CLEANFILES = mcron.c From df4fa60a031e30eff00c2fa06b0ea23d4e50b057 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 1 Jul 2015 01:05:34 +0200 Subject: [PATCH 036/239] Fix package name and bug reports email address. Conflicts: ChangeLog configure.ac --- ChangeLog | 19 +++++++++++++++++++ configure.ac | 3 ++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 806a03f..9675111 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2015-07-01 Mathieu Lirzin + + * configure.ac: Fix package name and bug reports email address. + + +2015-06-27 Mathieu Lirzin + + Use a more conventional build system. + * bootstrap: New convenient build script. + * README--git: Document it. + * makefile.am: Capitalize file name. + * makefile.ed: Likewise. + * scm/mcron/makefile: Likewise. + * Makefile.am: New file. + * Makefile.ed: Likewise. + * scm/mcron/Makefile: Likewise. + * .gitignore: Adapt to them. + + 2015-06-26 Mathieu Lirzin Fix build of the manual. diff --git a/configure.ac b/configure.ac index b4ec9f6..a3b84e6 100644 --- a/configure.ac +++ b/configure.ac @@ -22,7 +22,8 @@ AC_PREREQ(2.61) -AC_INIT([mcron], [1.0.8], [dale_mellor@users.sourceforge.net]) +AC_INIT([GNU Mcron], [1.0.8], [bug-mcron@gnu.org]) +AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE From 024027ae2dcc425f7a3bf5bf3ff3671833b02ce6 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Mon, 6 Jul 2015 05:46:30 +0100 Subject: [PATCH 037/239] Have a new directory to get rid of with maintainer-clean. --- ChangeLog | 27 ++------------------------- README--git | 20 -------------------- makefile.am | 6 +++++- 3 files changed, 7 insertions(+), 46 deletions(-) delete mode 100644 README--git diff --git a/ChangeLog b/ChangeLog index 9675111..7546ceb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,33 +3,10 @@ * configure.ac: Fix package name and bug reports email address. -2015-06-27 Mathieu Lirzin - - Use a more conventional build system. - * bootstrap: New convenient build script. - * README--git: Document it. - * makefile.am: Capitalize file name. - * makefile.ed: Likewise. - * scm/mcron/makefile: Likewise. - * Makefile.am: New file. - * Makefile.ed: Likewise. - * scm/mcron/Makefile: Likewise. - * .gitignore: Adapt to them. - - 2015-06-26 Mathieu Lirzin - Fix build of the manual. - * mcron.texinfo.in: Move to ... - * doc/mcron.texi: ... Here. New file. - * doc/config.texi.in: New file. - * configure.ac: Adapt to it. - * makefile.am: Likewise. - * .gitignore: Likewise. - * README--git: Likewise. + * Fix build of the manual. - Add missing 'makefile.am'. - * scm/mcron/makefile.am: New file. * .gitignore: Ignore 'mcron' only in the top-level directory. @@ -193,7 +170,7 @@ ________________________________________________________________________________ -Copyright (C) 2003, 2005, 2006, 2014 Dale Mellor +Copyright (C) 2003, 2005, 2006, 2014, 2015 Dale Mellor Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright diff --git a/README--git b/README--git deleted file mode 100644 index 9ebaa0d..0000000 --- a/README--git +++ /dev/null @@ -1,20 +0,0 @@ -GNU mcron --- README--git -*-text-*- - - Copyright (C) 2012, 2014 Dale Mellor - Copyright (C) 2015 Mathieu Lirzin - - Copying and distribution of this file, with or without modification, - are permitted in any medium without royalty provided the copyright - notice and this notice are preserved. - - -If you have pulled mcron from the GIT repository, these are the steps you will -need to take to build it the first time: - -1) autoreconf -vfi -2) ./configure --prefix={wherever} -3) make install - - -After that it should just be a simple matter of typing `make install' when you -want to build a version with changes in it. diff --git a/makefile.am b/makefile.am index 65b10d8..23384bd 100644 --- a/makefile.am +++ b/makefile.am @@ -51,7 +51,7 @@ mcron.c : scm/mcron/main.scm scm/mcron/crontab.scm makefile.ed mcron.c.template @rm -f mcron.escaped.scm > /dev/null 2>&1 -#full program prefix +# Full program prefix. fpp = $(DESTDIR)$(bindir)/@real_program_prefix@ @@ -83,3 +83,7 @@ uninstall-hook: $(dist_man_MANS): mcron.c $(HELP2MAN) -n 'a program to run tasks at regular (or not) intervals' \ ./mcron > $@ + + +maintainer-clean-local: + rm -r build-aux From c0a6eb14c257a47e9573631e5ac09e6528fba377 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Thu, 22 Oct 2015 06:59:21 +0100 Subject: [PATCH 038/239] Taken on board suggestions of Mathieu Lirzin as per e-mails to the bug-mcron@gnu.org mailing list around September 2015. --- .gitignore | 13 +- AUTHORS | 5 +- ChangeLog | 41 +- TODO | 9 + configure.ac | 25 +- doc/fdl.texi | 505 +++++++++++++++++++++++ doc/mcron.texi | 6 + makefile.am | 33 +- makefile.ed | 34 -- mcron.c | 115 ++++++ mcron.c.template | 120 ------ scm/mcron/config.scm.in | 4 + scm/mcron/crontab.scm | 4 +- scm/mcron/environment.scm | 55 ++- scm/mcron/job-specifier.scm | 21 +- scm/mcron/main.scm | 653 ++++++++++++++---------------- scm/mcron/makefile.am | 65 ++- scm/mcron/mcron-core.scm | 96 +++-- scm/mcron/redirect.scm | 1 + scm/mcron/vixie-specification.scm | 14 +- 20 files changed, 1155 insertions(+), 664 deletions(-) create mode 100644 doc/fdl.texi delete mode 100644 makefile.ed create mode 100644 mcron.c delete mode 100644 mcron.c.template diff --git a/.gitignore b/.gitignore index 2bedd6e..0af9e30 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,20 @@ *~ +*.o +*.go .deps INSTALL aclocal.m4 autom4te.cache +/build-aux/compile +/build-aux/config.guess +/build-aux/config.sub +/build-aux/depcomp +/build-aux/install-sh +/build-aux/mdate-sh +/build-aux/missing +/build-aux/texinfo.tex compile +config.cache config.log config.scm config.status @@ -20,8 +31,6 @@ install-sh makefile makefile.in /mcron -mcron.c /mdate-sh -*.o missing texinfo.tex diff --git a/AUTHORS b/AUTHORS index 821f761..2e2c046 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,6 +1,6 @@ Authors of GNU mcron. - Copyright (C) 2003, 2005, 2006 Dale Mellor + Copyright (C) 2003, 2005, 2006, 2015 Dale Mellor Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright @@ -16,3 +16,6 @@ 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. + +Further contributions have been received from Sergey Poznyakoff and Mathieu + Lirzin, and incorporated where appropriate. diff --git a/ChangeLog b/ChangeLog index 7546ceb..a458747 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2015-10-22 Dale Mellor + + Taken on board suggestions of Mathieu Lirzin. This is mostly + cosmetic code re-arranging and refresh for newer features of + guile, but also: + + * Eliminate the hacked embedding of the main scheme unit into the + C source code. + + * Compile all the guile modules before installation. + + + 2015-07-01 Mathieu Lirzin * configure.ac: Fix package name and bug reports email address. @@ -10,7 +23,7 @@ * .gitignore: Ignore 'mcron' only in the top-level directory. -2014-05-25 Dale Mellor +2014-05-25 Dale Mellor * Juggled build infrastructure so that we can make the minimal man page in the proper autotools way. @@ -18,14 +31,14 @@ * configure.ac: version to 1.0.8. -2014-04-28 Dale Mellor +2014-04-28 Dale Mellor * We now run against, and require, guile-2.0. * configure.ac: version to 1.0.7. -2012-02-04 Dale Mellor +2012-02-04 Dale Mellor * main.scm: added search for initial files in $XDG_CONFIG_HOME/cron directory, defaulting to ~/.config/cron if @@ -34,7 +47,7 @@ standards). -2010-06-13 Dale Mellor +2010-06-13 Dale Mellor * configure.ac: added --enable-no-vixie-clobber argument to configure so that the root user can avoid overwriting a legacy @@ -47,7 +60,7 @@ former is not supplied with the latest automake (1.11). -2008-02-21 Dale Mellor +2008-02-21 Dale Mellor * ALL FILES: Replaced version 2 GPL notices with version 3 ones. @@ -58,7 +71,7 @@ * configure.ac: Bumped version to 1.0.4. -2008-01-25 Dale Mellor +2008-01-25 Dale Mellor * main.scm (command-type): Files which are listed on the command line are assumed to be guile configurations if they do not end in @@ -76,7 +89,7 @@ * Version is currently at 1.0.3. -2005-09-02 Dale Mellor +2005-09-02 Dale Mellor * makefile.am, mcron.c.template (main): Modified install-exec-hook so that a proper installation of a Vixie-compatible cron only @@ -93,7 +106,7 @@ * Bumped version to 1.0.2. -2004-05-15 Dale Mellor +2004-05-15 Dale Mellor * Modified all auxiliary files to reflect that the package is now properly homed at www.gnu.org. @@ -101,7 +114,7 @@ * Bumped version to 1.0.1. -2003-12-11 Dale Mellor +2003-12-11 Dale Mellor * Modified all auxiliary files to reflect that we are now a GNU package. @@ -109,7 +122,7 @@ * Bumped version to 1.0.0. -2003-12-07 Dale Mellor +2003-12-07 Dale Mellor * configure.ac: Added switches for files and directories used by mcron: --spool-dir, --socket-file, --allow-file, --deny-file, @@ -118,14 +131,14 @@ manual). -2003-12-05 Dale Mellor +2003-12-05 Dale Mellor * configure.ac: Added test for guile version >= 1.6.4. * bumped version to 0.99.4. -2003-08-03 Dale Mellor +2003-08-03 Dale Mellor * Third cut, fully functional, modular, production quality, still needs testing... @@ -136,7 +149,7 @@ * Bumped version to 0.99.3. -2003-07-20 Dale Mellor +2003-07-20 Dale Mellor * Second cut, now _really_ fully functional (100% Vixie compatible), production quality code, still needs lots of testing @@ -154,7 +167,7 @@ * Bumped version to 0.99.2. -2003-06-28 Dale Mellor +2003-06-28 Dale Mellor * First cut, fully functional, production quality code, just needs testing... diff --git a/TODO b/TODO index 9ed8bca..7572f19 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,6 @@ GNU mcron --- TODO -*-text-*- + Copyright (C) 2015 Mathieu Lirzin Copyright (C) 2003, 2005, 2006, 2014 Dale Mellor Copying and distribution of this file, with or without modification, @@ -19,6 +20,14 @@ Maybe in the near future... core or other users' files up. Then allow scheme code in the system crontabs. + * Make mcron behavior not depend on the name used to invoke it, to conform + to GNU standards. + + * Provide a test suite using SRFI-64 API. + . + + * Internationalize Mcron using GNU Gettext and ask the Translation + Project to handle the localization. There are no plans to actually do the following any time soon... diff --git a/configure.ac b/configure.ac index a3b84e6..149653d 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,7 @@ # Process this file with autoconf to produce a configure script. -# Copyright (C) 2003, 2005, 2012, 2014 Dale Mellor -# Copyright (C) 2015 Mathieu Lirzin +# Copyright (C) 2003, 2005, 2012, 2014, 2015 Dale Mellor # # This file is part of GNU mcron. # @@ -24,8 +23,13 @@ AC_PREREQ(2.61) AC_INIT([GNU Mcron], [1.0.8], [bug-mcron@gnu.org]) AC_CONFIG_AUX_DIR([build-aux]) -AM_INIT_AUTOMAKE +AM_INIT_AUTOMAKE([silent-rules]) +# Enable silent rules by default. +AM_SILENT_RULES([yes]) + +guilemoduledir="${datarootdir}/guile/site/2.0" +AC_SUBST([guilemoduledir]) AC_MSG_CHECKING([whether debugging is requested]) AC_ARG_ENABLE(debug, @@ -45,12 +49,19 @@ AC_SUBST(CONFIG_DEBUG) # We have no interest (hence a no-op), but Debian wants this. AC_ARG_ENABLE(maintainer-mode) - +AC_CANONICAL_HOST AC_PROG_AWK AC_PROG_EGREP AM_PROG_CC_C_O -PKG_CHECK_MODULES(GUILE, guile-2.0) +PKG_CHECK_MODULES([GUILE], [guile-2.0 >= 2.0.7]) +AC_PATH_PROG([GUILE], [guile]) + +# search guild +AC_PATH_PROG([GUILD], [guild]) +if test "x$GUILD" = "x"; then + AC_MSG_ERROR(['guild' binary not found; please check your guile-2.x installation.]) +fi # Checks for programs. @@ -64,10 +75,6 @@ AC_CHECK_PROGS(HEAD, head) if test "x$ac_cv_prog_HEAD" = "x"; then AC_MSG_ERROR(head not found) fi -AC_CHECK_PROGS(ED, ed) -if test "x$ac_cv_prog_ED" = "x"; then - AC_MSG_ERROR(ed not found) -fi AC_CHECK_PROGS(WHICH, which) if test "x$ac_cv_prog_WHICH" = "x"; then AC_MSG_ERROR(which not found) diff --git a/doc/fdl.texi b/doc/fdl.texi new file mode 100644 index 0000000..9c3bbe5 --- /dev/null +++ b/doc/fdl.texi @@ -0,0 +1,505 @@ +@c The GNU Free Documentation License. +@center Version 1.3, 3 November 2008 + +@c This file is intended to be included within another document, +@c hence no sectioning command or @node. + +@display +Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. +@uref{http://fsf.org/} + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. +@end display + +@enumerate 0 +@item +PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document @dfn{free} in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of ``copyleft'', which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + +@item +APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The ``Document'', below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as ``you''. You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A ``Modified Version'' of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A ``Secondary Section'' is a named appendix or a front-matter section +of the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall +subject (or to related matters) and contains nothing that could fall +directly within that overall subject. (Thus, if the Document is in +part a textbook of mathematics, a Secondary Section may not explain +any mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The ``Invariant Sections'' are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The ``Cover Texts'' are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A ``Transparent'' copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not ``Transparent'' is called ``Opaque''. + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, La@TeX{} input +format, SGML or XML using a publicly available +DTD, and standard-conforming simple HTML, +PostScript or PDF designed for human modification. Examples +of transparent image formats include PNG, XCF and +JPG@. Opaque formats include proprietary formats that can be +read and edited only by proprietary word processors, SGML or +XML for which the DTD and/or processing tools are +not generally available, and the machine-generated HTML, +PostScript or PDF produced by some word processors for +output purposes only. + +The ``Title Page'' means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, ``Title Page'' means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +The ``publisher'' means any person or entity that distributes copies +of the Document to the public. + +A section ``Entitled XYZ'' means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as ``Acknowledgements'', +``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title'' +of such a section when you modify the Document means that it remains a +section ``Entitled XYZ'' according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + +@item +VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + +@item +COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. + +@item +MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +@enumerate A +@item +Use in the Title Page (and on the covers, if any) a title distinct +from that of the Document, and from those of previous versions +(which should, if there were any, be listed in the History section +of the Document). You may use the same title as a previous version +if the original publisher of that version gives permission. + +@item +List on the Title Page, as authors, one or more persons or entities +responsible for authorship of the modifications in the Modified +Version, together with at least five of the principal authors of the +Document (all of its principal authors, if it has fewer than five), +unless they release you from this requirement. + +@item +State on the Title page the name of the publisher of the +Modified Version, as the publisher. + +@item +Preserve all the copyright notices of the Document. + +@item +Add an appropriate copyright notice for your modifications +adjacent to the other copyright notices. + +@item +Include, immediately after the copyright notices, a license notice +giving the public permission to use the Modified Version under the +terms of this License, in the form shown in the Addendum below. + +@item +Preserve in that license notice the full lists of Invariant Sections +and required Cover Texts given in the Document's license notice. + +@item +Include an unaltered copy of this License. + +@item +Preserve the section Entitled ``History'', Preserve its Title, and add +to it an item stating at least the title, year, new authors, and +publisher of the Modified Version as given on the Title Page. If +there is no section Entitled ``History'' in the Document, create one +stating the title, year, authors, and publisher of the Document as +given on its Title Page, then add an item describing the Modified +Version as stated in the previous sentence. + +@item +Preserve the network location, if any, given in the Document for +public access to a Transparent copy of the Document, and likewise +the network locations given in the Document for previous versions +it was based on. These may be placed in the ``History'' section. +You may omit a network location for a work that was published at +least four years before the Document itself, or if the original +publisher of the version it refers to gives permission. + +@item +For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve +the Title of the section, and preserve in the section all the +substance and tone of each of the contributor acknowledgements and/or +dedications given therein. + +@item +Preserve all the Invariant Sections of the Document, +unaltered in their text and in their titles. Section numbers +or the equivalent are not considered part of the section titles. + +@item +Delete any section Entitled ``Endorsements''. Such a section +may not be included in the Modified Version. + +@item +Do not retitle any existing section to be Entitled ``Endorsements'' or +to conflict in title with any Invariant Section. + +@item +Preserve any Warranty Disclaimers. +@end enumerate + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled ``Endorsements'', provided it contains +nothing but endorsements of your Modified Version by various +parties---for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + +@item +COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled ``History'' +in the various original documents, forming one section Entitled +``History''; likewise combine any sections Entitled ``Acknowledgements'', +and any sections Entitled ``Dedications''. You must delete all +sections Entitled ``Endorsements.'' + +@item +COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. + +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. + +@item +AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an ``aggregate'' if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + +@item +TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled ``Acknowledgements'', +``Dedications'', or ``History'', the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + +@item +TERMINATION + +You may not copy, modify, sublicense, or distribute the Document +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense, or distribute it is void, and +will automatically terminate your rights under this License. + +However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally +terminates your license, and (b) permanently, if the copyright holder +fails to notify you of the violation by some reasonable means prior to +60 days after the cessation. + +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, receipt of a copy of some or all of the same material does +not give you any rights to use it. + +@item +FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. See +@uref{http://www.gnu.org/copyleft/}. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License ``or any later version'' applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. If the Document +specifies that a proxy can decide which future versions of this +License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the +Document. + +@item +RELICENSING + +``Massive Multiauthor Collaboration Site'' (or ``MMC Site'') means any +World Wide Web server that publishes copyrightable works and also +provides prominent facilities for anybody to edit those works. A +public wiki that anybody can edit is an example of such a server. A +``Massive Multiauthor Collaboration'' (or ``MMC'') contained in the +site means any set of copyrightable works thus published on the MMC +site. + +``CC-BY-SA'' means the Creative Commons Attribution-Share Alike 3.0 +license published by Creative Commons Corporation, a not-for-profit +corporation with a principal place of business in San Francisco, +California, as well as future copyleft versions of that license +published by that same organization. + +``Incorporate'' means to publish or republish a Document, in whole or +in part, as part of another Document. + +An MMC is ``eligible for relicensing'' if it is licensed under this +License, and if all works that were first published under this License +somewhere other than this MMC, and subsequently incorporated in whole +or in part into the MMC, (1) had no cover texts or invariant sections, +and (2) were thus incorporated prior to November 1, 2008. + +The operator of an MMC Site may republish an MMC contained in the site +under CC-BY-SA on the same site at any time before August 1, 2009, +provided the MMC is eligible for relicensing. + +@end enumerate + +@page +@heading ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + +@smallexample +@group + Copyright (C) @var{year} @var{your name}. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.3 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover + Texts. A copy of the license is included in the section entitled ``GNU + Free Documentation License''. +@end group +@end smallexample + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the ``with@dots{}Texts.''@: line with this: + +@smallexample +@group + with the Invariant Sections being @var{list their titles}, with + the Front-Cover Texts being @var{list}, and with the Back-Cover Texts + being @var{list}. +@end group +@end smallexample + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. + +@c Local Variables: +@c ispell-local-pdict: "ispell-dict" +@c End: diff --git a/doc/mcron.texi b/doc/mcron.texi index cb97a06..27cd1b7 100644 --- a/doc/mcron.texi +++ b/doc/mcron.texi @@ -63,6 +63,7 @@ running jobs at scheduled times. * Syntax:: All the possibilities for configuring cron jobs. * Invoking:: What happens when you run the mcron command. * Guile modules:: Incorporating mcron into another Guile program. +* GNU Free Documentation License:: The license of this manual. * Index:: The complete index. @detailmenu @@ -1329,6 +1330,11 @@ Once this module has been declared in a program, a crontab file can be used to augment the current job list with a call to @code{read-vixie-file}. +@node GNU Free Documentation License +@appendix GNU Free Documentation License + +@include fdl.texi + @node Index, , Guile modules, Top @unnumbered Index diff --git a/makefile.am b/makefile.am index 23384bd..0afa5fc 100644 --- a/makefile.am +++ b/makefile.am @@ -1,6 +1,5 @@ ## Makefile for the toplevel directory of mcron. -## Copyright (C) 2003 Dale Mellor -## Copyright (C) 2015 Mathieu Lirzin +## Copyright (C) 2003, 2015 Dale Mellor ## # This file is part of GNU mcron. # @@ -17,20 +16,13 @@ # You should have received a copy of the GNU General Public License along # with GNU mcron. If not, see . -## Process this file with automake to produce Makefile.in +## Process this file with automake to produce makefile.in SUBDIRS = scm/mcron . -ED = @ED@ # !!!! Are these needed? CP = @CP@ -MAINTAINERCLEANFILES = configure makefile makefile.in config.guess config.sub \ - install-sh missing texinfo.tex INSTALL \ - aclocal.m4 compile depcomp doc/mcron.1 - -CLEANFILES = mcron.c - -EXTRA_DIST = makefile.ed mcron.c.template BUGS +EXTRA_DIST = BUGS info_TEXINFOS = doc/mcron.texi @@ -42,14 +34,7 @@ mcron_LDADD = @GUILE_LIBS@ # The second option is so that we can execute the binary in the local directory, # in turn so that we can do mcron --help during the build process. -mcron_CFLAGS = @GUILE_CFLAGS@ -DGUILE_LOAD_PATH=\"$(datadir):./scm:...\" - - -mcron.c : scm/mcron/main.scm scm/mcron/crontab.scm makefile.ed mcron.c.template - @echo 'Building mcron.c...' - @$(ED) < makefile.ed > /dev/null 2>&1 - @rm -f mcron.escaped.scm > /dev/null 2>&1 - +mcron_CFLAGS = @GUILE_CFLAGS@ -DGUILE_LOAD_PATH=\"$(datadir):./scm:...\" # Full program prefix. fpp = $(DESTDIR)$(bindir)/@real_program_prefix@ @@ -79,11 +64,15 @@ uninstall-hook: # Not part of formal package building, but a rule for manual use to get the -# elemental man page. Will only work once the mcron program is installed. -$(dist_man_MANS): mcron.c +# elemental man page. +doc/mcron.1 : mcron $(HELP2MAN) -n 'a program to run tasks at regular (or not) intervals' \ - ./mcron > $@ + ./mcron > doc/mcron.1 +MAINTAINERCLEANFILES = configure makefile makefile.in config.guess config.sub \ + install-sh missing texinfo.tex INSTALL \ + aclocal.m4 compile depcomp doc/mcron.1 + maintainer-clean-local: rm -r build-aux diff --git a/makefile.ed b/makefile.ed deleted file mode 100644 index 7047ec7..0000000 --- a/makefile.ed +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (C) 2003 Dale Mellor -# -# This file is part of GNU mcron. -# -# GNU mcron is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free -# Software Foundation, either version 3 of the License, or (at your option) -# any later version. -# -# GNU mcron is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along -# with GNU mcron. If not, see . -# -# -# -e scm/mcron/main.scm -/\(load "crontab.scm"\)/d --1r scm/mcron/crontab.scm -%s/\\/\\\\/g -%s/"/\\"/g -%s/ *;;.*$/ /g -g/^ *$/d -%s/^/\"/ -%s/$/\"/ -w mcron.escaped.scm -e mcron.c.template -/GUILE_PROGRAM_GOES_HERE/d --1r mcron.escaped.scm -w mcron.c -q diff --git a/mcron.c b/mcron.c new file mode 100644 index 0000000..3776632 --- /dev/null +++ b/mcron.c @@ -0,0 +1,115 @@ +/* mcron.c -- Run the mcron program. + * + * Copyright (C) 2015 Mathieu Lirzin + * Copyright (C) 2003, 2014 Dale Mellor + * + * This file is part of GNU Mcron. + * + * GNU Mcron is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * GNU Mcron is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with GNU Mcron. If not, see . + */ + + +/* + * This C code represents the thinnest possible wrapper around the Guile code + * which constitutes all the functionality of the mcron program. There are + * two plus one reasons why we need to do this, and one very unfortunate + * consequence. + * + * Firstly, SUID does not work on an executable script. In the end, it is + * the execution of the translator, in our case guile, which determines the + * effective user, and it is not wise to make the system guile installation + * SUID root! + * + * Secondly, executable scripts show up in ugly ways in listings of the + * system process table. Guile in particular, with its multi-line ``#! ...\ + * \n -s ...!#'' idiosyncracies shows up in process listings in a way that + * is difficult to determine what program is actually running. + * + * A third reason for the C wrapper which might be mentioned is that a + * security-conscious system administrator can choose to only install a + * binary, thus removing the possibility of a user studying a guile script + * and working out ways of hacking it to his own ends, or worse still + * finding a way to modify it to his own ends. + * + * Unfortunately, running the guile script from inside a C program means + * that the sigaction function does not work. Instead, it is necessary to + * perform the signal processing in C. + */ + + + +#include +#include +#include +#include + + + +/* Handle the signal and exit. All signals that mcron handles will produce + * the same behavior so we don't need to use the signal value in the + * implementation. */ + +static void +react_to_terminal_signal (int signal) +{ + scm_c_eval_string ("(delete-run-file)"); + exit (1); +} + + + +/* Set up all the signal handlers as required by the cron personality. This + * is necessary to perform the signal processing in C because the sigaction + * function won't work when called from Guile; this function is called from + * the Guile universe. */ + +static SCM +set_cron_signals () +{ + static struct sigaction sa; + + memset (&sa, 0, sizeof (sa)); + sa.sa_handler = react_to_terminal_signal; + sigaction (SIGTERM, &sa, 0); + sigaction (SIGINT, &sa, 0); + sigaction (SIGQUIT, &sa, 0); + sigaction (SIGHUP, &sa, 0); + + return SCM_BOOL_T; +} + + + +/* Launch the Mcron Guile main program. */ + +static void +inner_main (void *closure, int argc, char **argv) +{ + scm_set_current_module (scm_c_resolve_module ("mcron main")); + scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); + scm_c_eval_string ("(main)"); +} + + + +/* The real main function. Does nothing but start up the guile subsystem. */ + +int +main (int argc, char **argv) +{ + setenv ("GUILE_LOAD_PATH", GUILE_LOAD_PATH, 1); + scm_boot_guile (argc, argv, inner_main, 0); + + return 0; +} diff --git a/mcron.c.template b/mcron.c.template deleted file mode 100644 index e9a755d..0000000 --- a/mcron.c.template +++ /dev/null @@ -1,120 +0,0 @@ -/* -*-c-*- */ -/* - * Copyright (C) 2003, 2014 Dale Mellor - * - * This file is part of GNU mcron. - * - * GNU mcron is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * GNU mcron is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with GNU mcron. If not, see . - */ - - -/* - This C code represents the thinnest possible wrapper around the Guile code - which constitutes all the functionality of the mcron program. There are two - plus one reasons why we need to do this, and one very unfortunate - consequence. - - Firstly, SUID does not work on an executable script. In the end, it is - the execution of the translator, in our case guile, which determines the - effective user, and it is not wise to make the system guile installation - SUID root! - - Secondly, executable scripts show up in ugly ways in listings of the - system process table. Guile in particular, with its multi-line - #! ...\ \n -s ...!# - idiosyncracies shows up in process listings in a way that is difficult - to determine what program is actually running. - - A third reason for the C wrapper which might be mentioned is that a - security-conscious system administrator can choose to only install a - binary, thus removing the possibility of a user studying a guile script - and working out ways of hacking it to his own ends, or worse still - finding a way to modify it to his own ends. - - Unfortunately, running the guile script from inside a C program means - that the sigaction function does not work. Instead, it is necessary to - perform the signal processing in C. - - The guile code itself is substituted for the GU1LE_PROGRAM_GOES_HERE (sic) - token by the makefile, which processes the scheme to make it look like one - big string. -*/ - - - -#include -#include -#include - - - -/* This is a function designed to be installed as a signal handler, for signals - which are supposed to initiate shutdown of this program. It calls the scheme - procedure (see mcron.scm for details) to do all the work, and then exits. */ - -void -react_to_terminal_signal (int sig) -{ - scm_c_eval_string ("(delete-run-file)"); - exit (1); -} - - - -/* This is a function designed to be callable from scheme, and sets up all the - signal handlers required by the cron personality. */ - -SCM -set_cron_signals () -{ - static struct sigaction sa; - memset (&sa, 0, sizeof (sa)); - sa.sa_handler = react_to_terminal_signal; - sigaction (SIGTERM, &sa, 0); - sigaction (SIGINT, &sa, 0); - sigaction (SIGQUIT, &sa, 0); - sigaction (SIGHUP, &sa, 0); - - return SCM_BOOL_T; -} - - - -/* The effective main function (i.e. the one that actually does some work). We - register the function above with the guile system, and then execute the mcron - guile program. */ - -void -inner_main () -{ - scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); - - scm_c_eval_string ( - GUILE_PROGRAM_GOES_HERE - ); -} - - - -/* The real main function. Does nothing but start up the guile subsystem. */ - -int -main (int argc, char **argv) -{ - setenv ("GUILE_LOAD_PATH", GUILE_LOAD_PATH, 1); - - scm_boot_guile (argc, argv, inner_main, 0); - - return 0; -} diff --git a/scm/mcron/config.scm.in b/scm/mcron/config.scm.in index 6a0a85d..db2bc32 100644 --- a/scm/mcron/config.scm.in +++ b/scm/mcron/config.scm.in @@ -1,5 +1,6 @@ ;; -*-scheme-*- +;; Copyright (C) 2015 Mathieu Lirzin ;; Copyright (C) 2003 Dale Mellor ;; ;; This file is part of GNU mcron. @@ -23,8 +24,11 @@ (define-module (mcron config)) (define-public config-debug @CONFIG_DEBUG@) +(define-public config-package-name "@PACKAGE_NAME@") +(define-public config-package-version "@PACKAGE_VERSION@") (define-public config-package-string "@PACKAGE_STRING@") (define-public config-package-bugreport "@PACKAGE_BUGREPORT@") +(define-public config-package-url "@PACKAGE_URL@") (define-public config-sendmail "@SENDMAIL@") (define-public config-spool-dir "@CONFIG_SPOOL_DIR@") diff --git a/scm/mcron/crontab.scm b/scm/mcron/crontab.scm index 30e5592..6be5c61 100644 --- a/scm/mcron/crontab.scm +++ b/scm/mcron/crontab.scm @@ -221,8 +221,8 @@ ;; The user is being silly. The message here is identical to the one Vixie cron ;; used to put out, for total compatibility. - (else - (mcron-error 15 "usage error: file name must be specified for replace."))) + (else (mcron-error 15 + "usage error: file name must be specified for replace."))) )) ;; End of file-level let-scopes. diff --git a/scm/mcron/environment.scm b/scm/mcron/environment.scm index 9f694f1..f364a38 100644 --- a/scm/mcron/environment.scm +++ b/scm/mcron/environment.scm @@ -1,4 +1,4 @@ -;; Copyright (C) 2003 Dale Mellor +;; Copyright (C) 2003, 2015 Dale Mellor ;; ;; This file is part of GNU mcron. ;; @@ -31,42 +31,12 @@ (define-module (mcron environment) + #:use-module (srfi srfi-26) #:export (modify-environment clear-environment-mods append-environment-mods get-current-environment-mods-copy)) - - - -;; The env-alist is an association list of variable names and values. Variables -;; later in the list will take precedence over variables before. We return a -;; fixed-up version in which some variables are given specific default values -;; (which the user can override), and two variables which the user is not -;; allowed to control are added at the end of the list. - -(define (impose-default-environment env-alist passwd-entry) - (append `(("HOME" . ,(passwd:dir passwd-entry)) - ("CWD" . ,(passwd:dir passwd-entry)) - ("SHELL" . ,(passwd:shell passwd-entry)) - ("TERM" . #f) - ("TERMCAP" . #f)) - env-alist - `(("LOGNAME" . ,(passwd:name passwd-entry)) - ("USER" . ,(passwd:name passwd-entry))))) - - - - -;; Modify the UNIX environment for the current process according to the given -;; association list of variables, with the default variable values imposed. - -(define (modify-environment env-alist passwd-entry) - (for-each (lambda (variable) - (setenv (car variable) (cdr variable))) - (impose-default-environment env-alist passwd-entry))) - - ;; As we parse configuration files, we build up an alist of environment @@ -103,3 +73,24 @@ (set! current-environment-mods (append current-environment-mods (list (cons name value)))) #t) + + + +;; Modify the UNIX environment for the current process according to the given +;; association list of variables, with the default variable values imposed. + +(define (modify-environment env-alist passwd-entry) + (for-each (lambda (a) (setenv (car a) (cdr a))) + (let ((home-dir (passwd:dir passwd-entry)) + (user-name (passwd:name passwd-entry))) + (append + ;; Default environment variables which can be overidden by ENV. + `(("HOME" . ,home-dir) + ("CWD" . ,home-dir) + ("SHELL" . ,(passwd:shell passwd-entry)) + ("TERM" . #f) + ("TERMCAP" . #f)) + env-alist + ;; Environment variables with imposed values. + `(("LOGNAME" . ,user-name) + ("USER" . ,user-name)))))) diff --git a/scm/mcron/job-specifier.scm b/scm/mcron/job-specifier.scm index cce948c..7ed912b 100644 --- a/scm/mcron/job-specifier.scm +++ b/scm/mcron/job-specifier.scm @@ -34,7 +34,7 @@ set-configuration-time job find-best-next) - #:use-module (mcron core) + #:use-module (mcron mcron-core) #:use-module (mcron environment) #:use-module (mcron vixie-time) #:re-export (append-environment-mods)) @@ -203,11 +203,16 @@ (define configuration-user (getpw (getuid))) (define configuration-time (current-time)) + + (define (set-configuration-user user) (set! configuration-user (if (or (string? user) (integer? user)) (getpw user) user))) + + + (define (set-configuration-time time) (set! configuration-time time)) @@ -233,10 +238,9 @@ ((list? action) (lambda () (primitive-eval action))) ((string? action) (lambda () (system action))) (else - (throw 'mcron-error - 2 - "job: invalid second argument (action; should be lambda" - " function, string or list)")))) + (throw 'mcron-error 2 + "job: invalid second argument (action; should be lambda " + "function, string or list)")))) (time-proc (cond ((procedure? time-proc) time-proc) @@ -244,10 +248,9 @@ ((list? time-proc) (lambda (current-time) (primitive-eval time-proc))) (else - (throw 'mcron-error - 3 - "job: invalid first argument (next-time-function; should ") - "be function, string or list)"))) + (throw 'mcron-error 3 + "job: invalid first argument (next-time-function; " + "should be function, string or list)")))) (displayable (cond ((not (null? displayable)) (car displayable)) ((procedure? action) "Lambda function") diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index 36adef9..dc839cc 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -1,4 +1,4 @@ -;; Copyright (C) 2003, 2012 Dale Mellor +;; Copyright (C) 2003, 2012, 2015 Dale Mellor ;; ;; This file is part of GNU mcron. ;; @@ -16,34 +16,24 @@ ;; with GNU mcron. If not, see . - -;; This is the 'main' routine for the whole system; the top of this file is the -;; global entry point (after the minimal C wrapper, mcron.c.template); to all -;; intents and purposes the program is pure Guile and starts here. -;; -;; This file is built into mcron.c.template by the makefile, which stringifies -;; the whole lot, and escapes quotation marks and escape characters -;; accordingly. Bear this in mind when considering literal multi-line strings. -;; -;; (l0ad "crontab.scm") (sic) is inlined by the makefile. All other -;; functionality comes through modules in .../share/guile/site/mcron/*.scm. +(define-module (mcron main) + #:use-module (ice-9 getopt-long) + #:use-module (ice-9 rdelim) + #:use-module (ice-9 regex) + #:use-module (mcron config) + #:use-module (mcron mcron-core) + #:use-module (mcron job-specifier) + #:use-module (mcron vixie-specification) + #:use-module (srfi srfi-2) + #:use-module (srfi srfi-26) + #:export (delete-run-file + main)) -;; Pull in some constants set by the builder (via autoconf) at configuration -;; time. Turn debugging on if indicated. - -(use-modules (mcron config)) -(if config-debug (begin (debug-enable 'debug) - (debug-enable 'backtrace))) - - - -;; To determine the name of the program, scan the first item of the command line -;; backwards for the first non-alphabetic character. This allows names like -;; in.cron to be accepted as an invocation of the cron command. - -(use-modules (ice-9 regex) (ice-9 rdelim)) +;; Extract the actual command name from \a command. This returns the last +;; part of \a command without any non-alphabetic characters. For example +;; "in.cron" and "./mcron" will return respectively "cron" and "mcron". (define command-name (match:substring (regexp-exec (make-regexp "[[:alpha:]]*$") (car (command-line))))) @@ -51,49 +41,49 @@ ;; Code contributed by Sergey Poznyakoff. Print an error message (made up from -;; the parts of rest), and if the error is fatal (present and non-zero) then -;; exit to the system with this code. +;; the parts of \a rest), and if the \a exit-code error is fatal (present and +;; non-zero) then exit to the system with \a exit-code. (define (mcron-error exit-code . rest) (with-output-to-port (current-error-port) (lambda () - (for-each display (append (list command-name ": ") rest)) + (for-each display + (cons* command-name ": " rest)) (newline))) - (if (and exit-code (not (eq? exit-code 0))) - (primitive-exit exit-code))) + (when (and exit-code + (not (eq? exit-code 0))) + (primitive-exit exit-code))) -;; Code contributed by Sergey Poznyakoff. Execute body. If an 'mcron-error +;; Code contributed by Sergey Poznyakoff and improved upon by Mathieu Lirzin +;; with newer guile features. Execute the expressions. If an 'mcron-error ;; exception occurs, print its diagnostics and exit with its error code. -(defmacro catch-mcron-error (. body) - `(catch 'mcron-error - (lambda () - ,@body) - (lambda (key exit-code . msg) - (apply mcron-error exit-code msg)))) +(define-syntax-rule (catch-mcron-error exp ...) + (catch 'mcron-error + (lambda () exp ...) + (lambda (key exit-code . msg) + (apply mcron-error exit-code msg)))) -;; We will be doing a lot of testing of the command name, so it makes sense to -;; perform the string comparisons once and for all here. +;; One of the symbols \c mcron, \c crond or \c crontab according to the means +;; of our invocation. -(define command-type (cond ((string=? command-name "mcron") 'mcron) - ((or (string=? command-name "cron") - (string=? command-name "crond")) 'cron) - ((string=? command-name "crontab") 'crontab) - (else - (mcron-error 12 "The command name is invalid.")))) +(define command-type + (let ((command=? (cute string=? command-name <>))) + (cond ((command=? "mcron") 'mcron) + ((or (command=? "cron") (command=? "crond")) 'cron) + ((command=? "crontab") 'crontab) + (else (mcron-error 12 "The command name is invalid."))))) -;; There are a different set of options for the crontab personality compared to -;; all the others, with the --help and --version options common to all the +;; There are a different set of options for the crontab personality compared +;; to all the others, with the --help and --version options common to all the ;; personalities. -(use-modules (ice-9 getopt-long)) - (define options (catch 'misc-error @@ -120,79 +110,86 @@ '((version (single-char #\v) (value #f)) (help (single-char #\h) (value #f)))))) (lambda (key func fmt args . rest) - (mcron-error 1 (apply format (append (list #f fmt) args)))))) - -;; If the user asked for the version of this program, give it to him and get -;; out. - -(if (option-ref options 'version #f) - (begin - (display (string-append "\n -" command-name " (" config-package-string ")\n -Written by Dale Mellor\n -\n -Copyright (C) 2003, 2006, 2014 Dale Mellor\n -This is free software; see the source for copying conditions. There is NO\n -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n -")) - (quit))) + (mcron-error 1 (apply format (cons* #f fmt args)))))) -;; Likewise if the user requested the help text. +;; Display version information for \a command and quit. -(if (option-ref options 'help #f) - (begin - (display (string-append " -Usage: " (car (command-line)) -(case command-type +(define* (show-version #:optional (command command-name)) + (let* ((name config-package-name) + (short-name (cadr (string-split name #\space))) + (version config-package-version)) + (simple-format #t "~a (~a) ~a +Copyright (C) 2015 Free Software Foundation, Inc. - ((mcron) -" [OPTIONS] [FILES]\n -Run an mcron process according to the specifications in the FILES (`-' for\n -standard input), or use all the files in ~/.config/cron (or the \n -deprecated ~/.cron) with .guile or .vixie extensions.\n -\n - -v, --version Display version\n - -h, --help Display this help message\n - -sN, --schedule[=]N Display the next N jobs that will be run by mcron\n - -d, --daemon Immediately detach the program from the terminal\n - and run as a daemon process\n - -i, --stdin=(guile|vixie) Format of data passed as standard input or\n +License GPLv3+: GNU GPL version 3 or later +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law.\n" + command name version) + (quit))) + + + +;; Display where to get help and send bug reports. + +(define (show-package-information) + (simple-format #t "\nReport bugs to: ~a. +~a home page: <~a> +General help using GNU software: \n" + config-package-bugreport + config-package-name + config-package-url)) + + + +;; Display usage information and quit. + +(define (show-help) + (simple-format #t "Usage: ~a" command-name) + (display + (case command-type + ((mcron) + " [OPTIONS] [FILES] +Run an mcron process according to the specifications in the FILES (`-' for +standard input), or use all the files in ~/.config/cron (or the +deprecated ~/.cron) with .guile or .vixie extensions. + + -v, --version Display version + -h, --help Display this help message + -sN, --schedule[=]N Display the next N jobs that will be run by mcron + -d, --daemon Immediately detach the program from the terminal + and run as a daemon process + -i, --stdin=(guile|vixie) Format of data passed as standard input or file arguments (default guile)") + ((cron) + " [OPTIONS] +Unless an option is specified, run a cron daemon as a detached process, +reading all the information in the users' crontabs and in /etc/crontab. - ((cron) -" [OPTIONS]\n -Unless an option is specified, run a cron daemon as a detached process, \n -reading all the information in the users' crontabs and in /etc/crontab.\n -\n - -v, --version Display version\n - -h, --help Display this help message\n - -sN, --schedule[=]N Display the next N jobs that will be run by cron\n - -n, --noetc Do not check /etc/crontab for updates (HIGHLY\n + -v, --version Display version + -h, --help Display this help message + -sN, --schedule[=]N Display the next N jobs that will be run by cron + -n, --noetc Do not check /etc/crontab for updates (HIGHLY RECOMMENDED).") - - ((crontab) - (string-append " [-u user] file\n" - " " (car (command-line)) " [-u user] { -e | -l | -r }\n" - " (default operation is replace, per 1003.2)\n" - " -e (edit user's crontab)\n" - " -l (list user's crontab)\n" - " -r (delete user's crontab)\n")) - - (else "rubbish")) - -"\n\n -Report bugs to " config-package-bugreport ".\n -")) - (quit))) + ((crontab) + " [-u user] file + crontab [-u user] { -e | -l | -r } + (default operation is replace, per 1003.2) + -e (edit user's crontab) + -l (list user's crontab) + -r (delete user's crontab)") + (else "\nrubbish"))) + (newline) + (show-package-information) + (quit)) -;; This is called from the C front-end whenever a terminal signal is -;; received. We remove the /var/run/cron.pid file so that crontab and other -;; invocations of cron don't get the wrong idea that a daemon is currently -;; running. +;; Remove the /var/run/cron.pid file so that crontab and other invocations of +;; cron don't get the wrong idea that a daemon is currently running. This +;; procedure is called from the C front-end whenever a terminal signal is +;; received. (define (delete-run-file) (catch #t (lambda () (delete-file config-pid-file) @@ -202,47 +199,7 @@ Report bugs to " config-package-bugreport ".\n -;; 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. -;; -;; Otherwise, clear the MAILTO environment variable so that output from cron -;; jobs is sent to the various users (this may still be overridden in the -;; configuration files), and call the function in the C wrapper to set up -;; terminal signal responses to vector to the procedure above. The PID file will -;; be filled in properly later when we have forked our daemon process (but not -;; done if we are only viewing the schedules). - -(if (eq? command-type 'cron) - (begin - (if (not (eqv? (getuid) 0)) - (mcron-error 16 - "This program must be run by the root user (and should " - "have been installed as such).")) - (if (access? config-pid-file F_OK) - (mcron-error 1 - "A cron daemon is already running.\n" - " (If you are sure this is not true, remove the file\n" - " " - config-pid-file - ".)")) - (if (not (option-ref options 'schedule #f)) - (with-output-to-file config-pid-file noop)) - (setenv "MAILTO" #f) - (c-set-cron-signals))) - - - -;; Define the functions available to the configuration files. While we're here, -;; we'll get the core loaded as well. - -(use-modules (mcron core) - (mcron job-specifier) - (mcron vixie-specification)) - - - -;; Procedure to slurp the standard input into a string. +;; Return standard input as a string. (define (stdin->string) (with-output-to-string (lambda () (do ((in (read-char) (read-char))) @@ -251,183 +208,83 @@ Report bugs to " config-package-bugreport ".\n -;; Now we have the procedures in place for dealing with the contents of -;; configuration files, the crontab personality is able to validate such -;; files. If the user requested the crontab personality, we load and run the -;; code here and then get out. +;; Return a thunk which process each file in \a directory with \a proc. The +;; \a directory must be a directory name. The \a proc argument must be a +;; procedure that takes one file name argument. -(if (eq? command-type 'crontab) - (begin - (load "crontab.scm") - (quit))) +(define (proc-in-directory directory proc) + (let ((dir (opendir directory))) + (do ((file-name (readdir dir) (readdir dir))) + ((eof-object? file-name) (closedir dir)) + (proc file-name)))) -;; Code contributed by Sergey Poznyakoff. Determine if the given file is a -;; regular file or not. +;; Process \a file-name according its extension. When \a guile-syntax? is \c +;; TRUE, force guile syntax usage. If \a file-name format is not recognized, +;; it is silently ignored (this deals properly with most editors' backup +;; files, for instance). -(define (regular-file? file) - (catch 'system-error - (lambda () - (eq? (stat:type (stat file)) 'regular)) - (lambda (key call fmt args . rest) - (mcron-error 0 (apply format (append (list #f fmt) args))) - #f))) +(define process-user-file + (let ((guile-regexp (make-regexp "\\.gui(le)?$")) + (vixie-regexp (make-regexp "\\.vix(ie)?$"))) + (lambda* (file-path #:optional assume-guile) + (cond ((string=? "-" file-path) + (if (string=? (option-ref options 'stdin "guile") "vixie") + (read-vixie-port (current-input-port)) + (eval-string (stdin->string)))) + ((regexp-exec vixie-regexp file-path) + (read-vixie-file file-path)) + ((or assume-guile + (regexp-exec guile-regexp file-path)) + (load file-path)))))) -;; Procedure which processes any configuration file according to the -;; extension. If a file is not recognized, it is silently ignored (this deals -;; properly with most editors' backup files, for instance). - -(define guile-file-regexp (make-regexp "\\.gui(le)?$")) -(define vixie-file-regexp (make-regexp "\\.vix(ie)?$")) - -(define (process-user-file file-path . assume-guile) - (cond ((string=? file-path "-") - (if (string=? (option-ref options 'stdin "guile") "vixie") - (read-vixie-port (current-input-port)) - (eval-string (stdin->string)))) - ((or (not (null? assume-guile)) - (regexp-exec guile-file-regexp file-path)) - (load file-path)) - ((regexp-exec vixie-file-regexp file-path) - (read-vixie-file file-path)))) - - - -;; Procedure to run through all the files in a user's ~/.cron and/or -;; $XDG_CONFIG_HOME/cron or ~/.config/cron directories (only happens under the -;; mcron personality). +;; Process files in $XDG_CONFIG_HOME/cron and/or ~/.cron directories (if +;; $XDG_CONFIG_HOME is not defined uses ~/.config/cron instead). (define (process-files-in-user-directory) (let ((errors 0) (home-directory (passwd:dir (getpw (getuid))))) - (map (lambda (config-directory) - (catch #t - (lambda () - (let ((directory (opendir config-directory))) - (do ((file-name (readdir directory) (readdir directory))) - ((eof-object? file-name) (closedir directory)) - (process-user-file (string-append config-directory - "/" - file-name))))) - (lambda (key . args) - (set! errors (1+ errors))))) - (list (string-append home-directory "/.cron") - (string-append (or (getenv "XDG_CONFIG_HOME") - (string-append home-directory "/.config")) - "/cron"))) - (if (eq? 2 errors) - (mcron-error 13 - "Cannot read files in your ~/.config/cron (or ~/.cron) " - "directory.")))) + (map (lambda (dir) + (catch #t + (lambda () + (proc-in-directory + dir + (lambda (file-name) + (process-user-file (string-append dir "/" file-name))))) + (lambda (key . args) + (set! errors (1+ errors))))) + (list (string-append home-directory "/.cron") + (string-append (or (getenv "XDG_CONFIG_HOME") + (string-append home-directory "/.config")) + "/cron"))) + (when (eq? 2 errors) + (mcron-error 13 + "Cannot read files in your ~/.config/cron (or ~/.cron) directory.")))) -;; 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. - -(define (valid-user user-name) - (setpwent) - (do ((entry (getpw) (getpw))) - ((or (not entry) - (string=? (passwd:name entry) user-name)) - (endpwent) - entry))) - - - -;; Procedure to process all the files in the crontab directory, making sure that -;; each file is for a legitimate user and setting the configuration-user to that -;; user. In this way, when the job procedure is run on behalf of the -;; configuration files, the jobs are registered with the system with the -;; appropriate user. Note that only the root user should be able to perform this -;; operation, but we leave it to the permissions on the /var/cron/tabs directory -;; to enforce this. - -(use-modules (srfi srfi-2)) ;; For and-let*. +;; Process all the files in the crontab directory. When the job procedure is +;; run on behalf of the configuration files, the jobs are registered on the +;; system with the appropriate user. Only root should be able to perform this +;; operation. The permissions on the /var/cron/tabs directory enforce this. (define (process-files-in-system-directory) (catch #t - (lambda () - (let ((directory (opendir config-spool-dir))) - (do ((file-name (readdir directory) (readdir directory))) - ((eof-object? file-name)) - (and-let* ((user (valid-user file-name))) - (set-configuration-user user) ;; / ?? !!!! - (catch-mcron-error - (read-vixie-file (string-append config-spool-dir - "/" - file-name))))))) - (lambda (key . args) - (mcron-error - 4 - "You do not have permission to access the system crontabs.")))) - - - -;; 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 -;; passed on the command line, or else all the ones in the user's .config/cron -;; (or .cron) directory. If we are running under the cron personality, we read -;; the /var/cron/tabs directory and also the /etc/crontab file. - -(case command-type - ((mcron) (if (null? (option-ref options '() '())) - (process-files-in-user-directory) - (for-each (lambda (file-path) - (process-user-file file-path #t)) - (option-ref options '() '())))) - - ((cron) (process-files-in-system-directory) - (use-system-job-list) - (catch-mcron-error - (read-vixie-file "/etc/crontab" parse-system-vixie-line)) - (use-user-job-list) - (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 "root") - (job '(- (next-minute-from (next-minute)) 6) - check-system-crontab - "/etc/crontab update checker."))))) - - - -;; If the user has requested a schedule of jobs that will run, we provide the -;; information here and then get out. -;; -;; Start by determining the number of time points in the future that output is -;; required for. This may be provided on the command line as a parameter to the -;; --schedule option, or else we assume a default of 8. Finally, ensure that the -;; count is some positive integer. - -(and-let* ((count (option-ref options 'schedule #f))) - (set! count (string->number count)) - (display (get-schedule (if (<= count 0) 1 count))) - (quit)) - - - -;; If we are supposed to run as a daemon process (either a --daemon option has -;; been explicitly used, or we are running as cron or crond), detach from the -;; terminal now. If we are running as cron, we can now write the PID file. - -(if (option-ref options 'daemon (eq? command-type 'cron)) - (begin - (if (not (eqv? (primitive-fork) 0)) - (quit)) - (setsid) - (if (eq? command-type 'cron) - (with-output-to-file config-pid-file - (lambda () (display (getpid)) (newline)))))) + (lambda () + (proc-in-directory + config-spool-dir + (lambda (user-name) + (and-let* ((user (false-if-exception (getpwnam user-name)))) + (set-configuration-user user) + (catch-mcron-error + (read-vixie-file + (string-append config-spool-dir "/" user-name))))))) + (lambda (key . args) + (mcron-error 4 + "You do not have permission to access the system crontabs.")))) @@ -436,32 +293,30 @@ option.\n") ;; inform the main wait-run-wait execution loop to listen for incoming messages ;; on this socket. -(define fd-list '()) - -(if (eq? command-type 'cron) - (catch #t - (lambda () - (let ((socket (socket AF_UNIX SOCK_STREAM 0))) - (bind socket AF_UNIX config-socket-file) - (listen socket 5) - (set! fd-list (list socket)))) - (lambda (key . args) - (delete-file config-pid-file) - (mcron-error 1 - "Cannot bind to UNIX socket " - config-socket-file)))) - +(define (cron-file-descriptors) + (if (eq? command-type 'cron) + (catch #t + (lambda () + (let ((socket (socket AF_UNIX SOCK_STREAM 0))) + (bind socket AF_UNIX config-socket-file) + (listen socket 5) + (list socket))) + (lambda (key . args) + (delete-file config-pid-file) + (mcron-error 1 + "Cannot bind to UNIX socket " config-socket-file))) + '())) -;; This function is called whenever a message comes in on the above socket. We -;; read a user name from the socket, dealing with the "/etc/crontab" special +;; Read a user name from the socket, dealing with the /etc/crontab special ;; case, remove all the user's jobs from the job list, and then re-read the -;; user's updated file. In the special case we drop all the system jobs and -;; re-read the /etc/crontab file. +;; user's updated file. In the special case drop all the system jobs and +;; re-read the /etc/crontab file. This function should be called whenever a +;; message comes in on the above socket. -(define (process-update-request) - (let* ((socket (car (accept (car fd-list)))) +(define (process-update-request fd-list) + (let* ((socket (car (accept (car fd-list)))) (user-name (read-line socket))) (close socket) (set-configuration-time (current-time)) @@ -475,29 +330,123 @@ option.\n") (let ((user (getpw user-name))) (remove-user-jobs user) (set-configuration-user user) - (read-vixie-file (string-append config-spool-dir "/" user-name))))))) + (read-vixie-file + (string-append config-spool-dir "/" user-name))))))) +;; Entry point. +;; +;; This is the 'main' routine for the whole system; this module is the global +;; entry point (after the minimal C wrapper); to all intents and purposes the +;; program is pure Guile and starts here. -;; Added by Sergey Poznyakoff. This no-op will collect zombie child processes -;; as soon as they die. This is a big improvement as previously they stayed -;; around the system until the next time mcron wakes to fire a new job off. +(define (main . args) + ;; Added by Sergey Poznyakoff. This no-op will collect zombie child processes + ;; as soon as they die. This is a big improvement as previously they stayed + ;; around the system until the next time mcron wakes to fire a new job off. + (when config-debug + (debug-enable 'backtrace)) + (when (option-ref options 'version #f) + (show-version)) + (when (option-ref options 'help #f) + (show-help)) + + ;; 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. + ;; + ;; Otherwise, clear the MAILTO environment variable so that output from cron + ;; jobs is sent to the various users (this may still be overridden in the + ;; configuration files), and call the function in the C wrapper to set up + ;; terminal signal responses to vector to the procedure above. The PID file + ;; will be filled in properly later when we have forked our daemon process + ;; (but not done if we are only viewing the schedules). + (when (eq? command-type 'cron) + (unless (eqv? (getuid) 0) + (mcron-error 16 + "This program must be run by the root user (and should have been " + "installed as such).")) + (when (access? config-pid-file F_OK) + (mcron-error 1 + "A cron daemon is already running.\n (If you are sure this is not" + " true, remove the file\n " config-pid-file ".)")) + (unless (option-ref options 'schedule #f) + (with-output-to-file config-pid-file noop)) + (setenv "MAILTO" #f) + ;; Mathieu Lirzin: At compile time, this yields a "possibly unbound + ;; variable" warning, but this is OK since it is bound in the C wrapper. + (c-set-cron-signals)) -;; Unfortunately it seems to interact badly with the select system call, -;; wreaking havoc... + ;; Now we have the procedures in place for dealing with the contents of + ;; configuration files, the crontab personality is able to validate such + ;; files. If the user requested the crontab personality, we load and run the + ;; code here and then get out. + (when (eq? command-type 'crontab) + (load "crontab.scm") + (quit)) -;; (sigaction SIGCHLD (lambda (sig) noop) SA_RESTART) + ;; 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 passed on the command line, or else all the ones in the user's + ;; .config/cron (or .cron) directory. If we are running under the cron + ;; personality, we read the /var/cron/tabs directory and also the + ;; /etc/crontab file. + (case command-type + ((mcron) + (if (null? (option-ref options '() '())) + (process-files-in-user-directory) + (for-each (lambda (file-path) (process-user-file file-path + 'guile-syntax)) + (option-ref options '() '())))) + ((cron) + (process-files-in-system-directory) + (use-system-job-list) + (catch-mcron-error (read-vixie-file "/etc/crontab" + parse-system-vixie-line)) + (use-user-job-list) + (unless (option-ref options 'noetc #f) + (display "\ +WARNING: cron will check for updates to /etc/crontab EVERY MINUTE. If you do +not use this file, or you are prepared to manually restart cron whenever you +make a change, then it is HIGHLY RECOMMENDED that you use the --noetc +option.\n") + (set-configuration-user "root") + (job '(- (next-minute-from (next-minute)) 6) + check-system-crontab + "/etc/crontab update checker.")))) + ;; If the user has requested a schedule of jobs that will run, we provide + ;; the information here and then get out. Start by determining the number + ;; of time points in the future that output is required for. This may be + ;; provided on the command line as a parameter to the --schedule option, or + ;; else we assume a default of 8. Finally, ensure that the count is some + ;; positive integer. + (and-let* ((count (option-ref options 'schedule #f))) + (set! count (string->number count)) + (display (get-schedule (max 1 count))) + (quit)) - -;; Now the main loop. Forever execute the run-job-loop procedure in the mcron -;; core, and when it drops out (can only be because a message has come in on the -;; socket) we process the socket request before restarting the loop again. -;; Sergey Poznyakoff: we can also drop out of run-job-loop because of a SIGCHLD, -;; so must test fd-list. - -(catch-mcron-error - (while #t - (run-job-loop fd-list) - (if (not (null? fd-list)) - (process-update-request)))) + ;; If we are supposed to run as a daemon process (either a --daemon option + ;; has been explicitly used, or we are running as cron or crond), detach + ;; from the terminal now. If we are running as cron, we can now write the + ;; PID file. + (when (option-ref options 'daemon (eq? command-type 'cron)) + (unless (eqv? (primitive-fork) 0) + (quit)) + (setsid) + (when (eq? command-type 'cron) + (with-output-to-file config-pid-file + (lambda () (display (getpid)) (newline))))) + + ;; Now the main loop. Forever execute the run-job-loop procedure in the + ;; mcron core, and when it drops out (can only be because a message has come + ;; in on the socket) we process the socket request before restarting the + ;; loop again. Sergey Poznyakoff: we can also drop out of run-job-loop + ;; because of a SIGCHLD, so must test fd-list. + (catch-mcron-error + (let ((fd-list (cron-file-descriptors))) + (while #t + (run-job-loop fd-list) + (unless (null? fd-list) + (process-update-request fd-list)))))) diff --git a/scm/mcron/makefile.am b/scm/mcron/makefile.am index 931b03b..e371311 100644 --- a/scm/mcron/makefile.am +++ b/scm/mcron/makefile.am @@ -1,15 +1,60 @@ -EXTRA_DIST = main.scm mcron-core.scm vixie-specification.scm \ - crontab.scm environment.scm job-specifier.scm redirect.scm \ - vixie-time.scm +## Makefile for the scm/mcron directory of mcron. -pkgdata_DATA = core.scm environment.scm job-specifier.scm redirect.scm \ - vixie-time.scm vixie-specification.scm config.scm +# Copyright (C) 2015 Mathieu Lirzin +# +# This file is part of GNU mcron. +# +# GNU mcron is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# GNU mcron is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU mcron. If not, see . + +## Process this file with automake to produce makefile.in. -# If you're wondering, the configure script keeps deleting all files with a name -# like core.*, so we have to keep re-making it (I lost a good day's work because -# of this). +MODULES = environment.scm \ + job-specifier.scm \ + main.scm \ + mcron-core.scm \ + redirect.scm \ + vixie-specification.scm \ + vixie-time.scm -core.scm : mcron-core.scm - $(CP) mcron-core.scm core.scm +GOBJECTS = $(MODULES:%.scm=%.go) config.go +nobase_dist_guilemodule_DATA = $(MODULES) crontab.scm +nobase_nodist_guilemodule_DATA = $(GOBJECTS) config.scm + +CLEANFILES = $(GOBJECTS) + +AM_V_GUILEC = $(AM_V_GUILEC_$(V)) +AM_V_GUILEC_ = $(AM_V_GUILEC_$(AM_DEFAULT_VERBOSITY)) +AM_V_GUILEC_0 = @echo " GUILEC" $@; + +# Unset 'GUILE_LOAD_COMPILED_PATH' altogether while compiling. Otherwise, if +# $GUILE_LOAD_COMPILED_PATH contains $(moduledir), we may find .go files in +# there that are newer than the local .scm files (for instance because the +# user ran 'make install' recently). When that happens, we end up loading +# those previously-installed .go files, which may be stale, thereby breaking +# the whole thing. +# +# XXX: Use the C locale for when Guile lacks +# . +.scm.go: + $(AM_V_GUILEC)$(MKDIR_P) `dirname "$@"` ; \ + unset GUILE_LOAD_COMPILED_PATH ; \ + LC_ALL=C \ + $(GUILD) compile \ + -L "$(top_builddir)/scm" -L "$(top_srcdir)/scm" \ + -Wformat -Wunbound-variable -Warity-mismatch \ + --target="$(host)" \ + -o "$@" "$<" + +SUFFIXES = .go diff --git a/scm/mcron/mcron-core.scm b/scm/mcron/mcron-core.scm index 518bcac..9b83faf 100644 --- a/scm/mcron/mcron-core.scm +++ b/scm/mcron/mcron-core.scm @@ -1,4 +1,4 @@ -;; Copyright (C) 2003 Dale Mellor +;; Copyright (C) 2003, 2015 Dale Mellor ;; ;; This file is part of GNU mcron. ;; @@ -17,8 +17,9 @@ -(define-module (mcron core) +(define-module (mcron mcron-core) #:use-module (mcron environment) + #:use-module (srfi srfi-9) #:export (add-job remove-user-jobs get-schedule @@ -38,7 +39,7 @@ ;; The list of all jobs known to the system. Each element of the list is ;; -;; (vector user next-time-function action environment displayable next-time) +;; (make-job user next-time-function action environment displayable next-time) ;; ;; where action must be a procedure, and the environment is an alist of ;; modifications that need making to the UNIX environment before the action is @@ -60,18 +61,17 @@ (define (use-system-job-list) (set! configuration-source 'system)) (define (use-user-job-list) (set! configuration-source 'user)) - - -;; Convenience functions for getting and setting the elements of a job object. - -(define (job:user job) (vector-ref job 0)) -(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:displayable job) (vector-ref job 4)) -(define (job:next-time job) (vector-ref job 5)) - - +;; A cron job. +(define-record-type + (make-job user time-proc action environment displayable next-time) + job? + (user job:user) ;string : user passwd entry + (time-proc job:next-time-function) ;proc : with one 'time' parameter + (action job:action) ;thunk : user's code + (environment job:environment) ;alist : environment variables + (displayable job:displayable) ;string : visible in schedule + (next-time job:next-time ;number : time in UNIX format + job:next-time-set!)) ;; Remove jobs from the user-job-list belonging to this user. @@ -97,12 +97,12 @@ (define (add-job time-proc action displayable configuration-time configuration-user) - (let ((entry (vector configuration-user - time-proc - action - (get-current-environment-mods-copy) - displayable - (time-proc configuration-time)))) + (let ((entry (make-job configuration-user + time-proc + action + (get-current-environment-mods-copy) + displayable + (time-proc configuration-time)))) (if (eq? configuration-source 'user) (set! user-job-list (cons entry user-job-list)) (set! system-job-list (cons entry system-job-list))))) @@ -165,18 +165,17 @@ (lambda () (do ((count count (- count 1))) ((eqv? count 0)) - (and-let* ((next-jobs (find-next-jobs)) - (time (car next-jobs)) - (date-string (strftime "%c %z\n" (localtime time)))) - (for-each (lambda (job) - (display date-string) - (display (job:displayable job)) - (newline)(newline) - (vector-set! job - 5 - ((job:next-time-function job) - (job:next-time job)))) - (cdr next-jobs))))))) + (and-let* + ((next-jobs (find-next-jobs)) + (time (car next-jobs)) + (date-string (strftime "%c %z\n" (localtime time)))) + (for-each (lambda (job) + (display date-string) + (display (job:displayable job)) + (newline)(newline) + (job:next-time-set! job ((job:next-time-function job) + (job:next-time job)))) + (cdr next-jobs))))))) @@ -195,22 +194,21 @@ ;; to run. (define (run-jobs jobs-list) - (for-each (lambda (job) - (if (eqv? (primitive-fork) 0) - (begin - (setgid (passwd:gid (job:user job))) - (setuid (passwd:uid (job:user job))) - (chdir (passwd:dir (job:user job))) - (modify-environment (job:environment job) (job:user job)) - ((job:action job)) - (primitive-exit 0)) - (begin - (set! number-children (+ number-children 1)) - (vector-set! job - 5 - ((job:next-time-function job) - (current-time)))))) - jobs-list)) + (for-each + (lambda (job) + (if (eqv? (primitive-fork) 0) + (begin + (setgid (passwd:gid (job:user job))) + (setuid (passwd:uid (job:user job))) + (chdir (passwd:dir (job:user job))) + (modify-environment (job:environment job) (job:user job)) + ((job:action job)) + (primitive-exit 0)) + (begin + (set! number-children (+ number-children 1)) + (job:next-time-set! job ((job:next-time-function job) + (current-time)))))) + jobs-list)) diff --git a/scm/mcron/redirect.scm b/scm/mcron/redirect.scm index 312b768..af763cb 100644 --- a/scm/mcron/redirect.scm +++ b/scm/mcron/redirect.scm @@ -31,6 +31,7 @@ (define-module (mcron redirect) #:export (with-mail-out) + #:use-module (ice-9 regex) #:use-module ((mcron config) :select (config-sendmail)) #:use-module (mcron vixie-time)) diff --git a/scm/mcron/vixie-specification.scm b/scm/mcron/vixie-specification.scm index ab002ba..e7fab0a 100644 --- a/scm/mcron/vixie-specification.scm +++ b/scm/mcron/vixie-specification.scm @@ -30,7 +30,7 @@ read-vixie-file check-system-crontab) #:use-module ((mcron config) :select (config-socket-file)) - #:use-module (mcron core) + #:use-module (mcron mcron-core) #:use-module (mcron job-specifier) #:use-module (mcron redirect) #:use-module (mcron vixie-time)) @@ -162,13 +162,11 @@ (parse-vixie-environment line) (parse-vixie-line line))) (lambda (key exit-code . msg) - (throw - 'mcron-error - exit-code - (apply string-append - (number->string report-line) - ": " - msg))))))))) + (throw 'mcron-error exit-code + (apply string-append + (number->string report-line) + ": " + msg))))))))) From b3202cecf6a051d726f9af5d080aeb89257b0a98 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Fri, 26 Jun 2015 19:30:24 +0200 Subject: [PATCH 039/239] build: Add missing 'makefile.am'. * scm/mcron/makefile.am: New file. * .gitignore: Ignore 'mcron' only in the top-level directory. --- .gitignore | 2 +- scm/mcron/makefile.am | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 scm/mcron/makefile.am diff --git a/.gitignore b/.gitignore index f8096eb..00fa239 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,7 @@ depcomp install-sh makefile makefile.in -mcron +/mcron mcron.c mcron.info *.o diff --git a/scm/mcron/makefile.am b/scm/mcron/makefile.am new file mode 100644 index 0000000..931b03b --- /dev/null +++ b/scm/mcron/makefile.am @@ -0,0 +1,15 @@ +EXTRA_DIST = main.scm mcron-core.scm vixie-specification.scm \ + crontab.scm environment.scm job-specifier.scm redirect.scm \ + vixie-time.scm + +pkgdata_DATA = core.scm environment.scm job-specifier.scm redirect.scm \ + vixie-time.scm vixie-specification.scm config.scm + + +# If you're wondering, the configure script keeps deleting all files with a name +# like core.*, so we have to keep re-making it (I lost a good day's work because +# of this). + +core.scm : mcron-core.scm + $(CP) mcron-core.scm core.scm + From 8f430594f4452c378de08177be187d1cb5de1cd0 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Fri, 26 Jun 2015 23:17:01 +0200 Subject: [PATCH 040/239] build: Fix build of the manual. * mcron.texinfo.in: Rename to ... * doc/mcron.texi: ... this. * doc/config.texi.in: New file. * configure.ac: Adapt to it. * makefile.am: Likewise. * .gitignore: Likewise. * README--git: Likewise. --- .gitignore | 9 ++- README--git | 11 ++-- configure.ac | 7 +- doc/config.texi.in | 5 ++ mcron.texinfo.in => doc/mcron.texi | 102 +++++++++++++++-------------- makefile.am | 11 ++-- 6 files changed, 79 insertions(+), 66 deletions(-) create mode 100644 doc/config.texi.in rename mcron.texinfo.in => doc/mcron.texi (95%) diff --git a/.gitignore b/.gitignore index 00fa239..2bedd6e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,13 +10,18 @@ config.status configure core.scm depcomp +/doc/.dirstamp +/doc/config.texi +/doc/mcron.info +/doc/mcron.1 +/doc/stamp-vti +/doc/version.texi install-sh makefile makefile.in /mcron mcron.c -mcron.info +/mdate-sh *.o -mcron.texinfo missing texinfo.tex diff --git a/README--git b/README--git index 43e9890..0b24ded 100644 --- a/README--git +++ b/README--git @@ -1,6 +1,7 @@ GNU mcron --- README--git -*-text-*- Copyright (C) 2012, 2014 Dale Mellor + Copyright (C) 2015, 2016 Mathieu Lirzin Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright @@ -10,13 +11,9 @@ GNU mcron --- README--git -*-text-*- If you have pulled mcron from the GIT repository, these are the steps you will need to take to build it the first time: -1) aclocal -2) autoconf -3) automake -a (will error) -4) ./configure (will error) -5) automake -a -6) ./configure --prefix={wherever} -7) make install +1) autoreconf -vfi +2) ./configure --prefix={wherever} +3) make install After that it should just be a simple matter of typing `make install' when you diff --git a/configure.ac b/configure.ac index 764ea03..fee17fc 100644 --- a/configure.ac +++ b/configure.ac @@ -3,6 +3,7 @@ # Copyright (C) 2003, 2005, 2012, 2014 Dale Mellor +# Copyright (C) 2015, 2016 Mathieu Lirzin # # This file is part of GNU mcron. # @@ -174,6 +175,8 @@ AC_SUBST(CONFIG_TMP_DIR) real_program_prefix=`echo $program_prefix | sed s/NONE//` AC_SUBST(real_program_prefix) - -AC_CONFIG_FILES(mcron.texinfo makefile scm/mcron/makefile scm/mcron/config.scm) +AC_CONFIG_FILES([doc/config.texi + makefile + scm/mcron/makefile + scm/mcron/config.scm]) AC_OUTPUT diff --git a/doc/config.texi.in b/doc/config.texi.in new file mode 100644 index 0000000..50d9a18 --- /dev/null +++ b/doc/config.texi.in @@ -0,0 +1,5 @@ +@set CONFIG_SOCKET_FILE @CONFIG_SOCKET_FILE@ +@set CONFIG_SPOOL_DIR @CONFIG_SPOOL_DIR@ +@set CONFIG_PID_FILE @CONFIG_PID_FILE@ +@set CONFIG_ALLOW_FILE @CONFIG_ALLOW_FILE@ +@set CONFIG_DENY_FILE @CONFIG_DENY_FILE@ diff --git a/mcron.texinfo.in b/doc/mcron.texi similarity index 95% rename from mcron.texinfo.in rename to doc/mcron.texi index bbf8e5b..cb97a06 100644 --- a/mcron.texinfo.in +++ b/doc/mcron.texi @@ -1,12 +1,14 @@ \input texinfo @c %**start of header @setfilename mcron.info -@settitle mcron @VERSION@ +@include config.texi +@include version.texi +@settitle mcron @value{VERSION} @c %**end of header @syncodeindex fn cp -@copying This manual is for GNU mcron (version @VERSION@), which is a +@copying This manual is for GNU mcron (version @value{VERSION}), which is a program for running jobs at scheduled times. Copyright @copyright{} 2003, 2005, 2006, 2012, 2014 Dale Mellor @@ -68,36 +70,36 @@ running jobs at scheduled times. Simple examples -* Guile Simple Examples:: -* Vixie Simple Examples:: +* Guile Simple Examples:: +* Vixie Simple Examples:: Full available syntax -* Guile Syntax:: -* Extended Guile examples:: -* Vixie Syntax:: +* Guile Syntax:: +* Extended Guile examples:: +* Vixie Syntax:: Extended Guile examples -* AT commands:: -* Every second Sunday:: -* Two hours every day:: -* Missing the first appointment:: -* Penultimate day of every month:: +* AT commands:: +* Every second Sunday:: +* Two hours every day:: +* Missing the first appointment:: +* Penultimate day of every month:: Vixie -* Paul Vixie's copyright:: -* Crontab file:: -* Incompatibilities with old Unices:: +* Paul Vixie's copyright:: +* Crontab file:: +* Incompatibilities with old Unices:: Detailed invoking -* Invoking mcron:: -* Invoking cron or crond:: +* Invoking mcron:: +* Invoking cron or crond:: * Invoking crontab:: * Behaviour on laptops:: -* Exit codes:: +* Exit codes:: Guile modules @@ -182,8 +184,8 @@ been to allow such simple specifications to be made easily. The examples show how to create the command descriptions, and subsequently how to run mcron to make them happen. @menu -* Guile Simple Examples:: -* Vixie Simple Examples:: +* Guile Simple Examples:: +* Vixie Simple Examples:: @end menu @node Guile Simple Examples, Vixie Simple Examples, Simple examples, Simple examples @@ -258,9 +260,9 @@ on your system, as root. @node Syntax, Invoking, Simple examples, Top @chapter Full available syntax @menu -* Guile Syntax:: -* Extended Guile examples:: -* Vixie Syntax:: +* Guile Syntax:: +* Extended Guile examples:: +* Vixie Syntax:: @end menu @node Guile Syntax, Extended Guile examples, Syntax, Syntax @section Guile Syntax @@ -392,11 +394,11 @@ they seem. The following examples illustrate some pitfalls, and demonstrate how to code around them. @menu -* AT commands:: -* Every second Sunday:: -* Two hours every day:: -* Missing the first appointment:: -* Penultimate day of every month:: +* AT commands:: +* Every second Sunday:: +* Two hours every day:: +* Missing the first appointment:: +* Penultimate day of every month:: @end menu @node AT commands, Every second Sunday, Extended Guile examples, Extended Guile examples @@ -545,9 +547,9 @@ the variable and runs the command in the user's default shell, as advertised by the /etc/passwd file. @menu -* Paul Vixie's copyright:: -* Crontab file:: -* Incompatibilities with old Unices:: +* Paul Vixie's copyright:: +* Crontab file:: +* Incompatibilities with old Unices:: @end menu @@ -796,11 +798,11 @@ place in the part which implements the mcron personality. @menu -* Invoking mcron:: -* Invoking cron or crond:: +* Invoking mcron:: +* Invoking cron or crond:: * Invoking crontab:: * Behaviour on laptops:: -* Exit codes:: +* Exit codes:: @end menu @node Invoking mcron, Invoking cron or crond, Invoking, Invoking @@ -893,21 +895,21 @@ standard output. @cindex invoking cron @cindex crond, invokation @cindex invoking crond -@cindex @CONFIG_SPOOL_DIR@ -@cindex @CONFIG_SOCKET_FILE@ +@cindex @value{CONFIG_SPOOL_DIR} +@cindex @value{CONFIG_SOCKET_FILE} NOTE THAT THIS SECTION ONLY APPLIES IF THE @code{cron} or @code{crond}, and @code{crontab} PROGRAMS HAVE BEEN INSTALLED BY THE SYSTEM ADMINISTRATOR. If the program runs by the name of @code{cron} or @code{crond}, then -it will read all the files in @code{@CONFIG_SPOOL_DIR@} (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 +it will read all the files in @code{@value{CONFIG_SPOOL_DIR}} (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{@CONFIG_SOCKET_FILE@}, 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. +@code{@value{CONFIG_SOCKET_FILE}}, 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 @@ -1060,7 +1062,7 @@ No problems. @item 1 An attempt has been made to start cron but there is already a -@CONFIG_PID_FILE@ file. If there really is no other cron daemon +@value{CONFIG_PID_FILE} file. If there really is no other cron daemon running (this does not include invokations of mcron) then you should remove this file before attempting to run cron. @@ -1078,9 +1080,9 @@ to be specified in one of these forms. @item 4 An attempt to run cron has been made by a user who does not have -permission to access the crontabs in @CONFIG_SPOOL_DIR@. These files -should be readable only by root, and the cron daemon must be run as -root. +permission to access the crontabs in @value{CONFIG_SPOOL_DIR}. These +files should be readable only by root, and the cron daemon must be run +as root. @item 5 An attempt to run mcron has been made, but there are no jobs to @@ -1088,7 +1090,7 @@ schedule! @item 6 The system administrator has blocked this user from using crontab with -the files @CONFIG_ALLOW_FILE@ and @CONFIG_DENY_FILE@. +the files @value{CONFIG_ALLOW_FILE} and @value{CONFIG_DENY_FILE}. @item 7 Crontab has been run with more than one of the arguments @code{-l}, @@ -1248,7 +1250,7 @@ This module is introduced to a program with the command @code{(use-modules (mcron redirect))}. This module provides the @code{with-mail-out} function, described -fully in @ref{Guile Syntax}. +fully in @ref{Guile Syntax}. @node The vixie-time module, The job-specifier module, The redirect module, Guile modules @section The vixie-time module @@ -1325,7 +1327,7 @@ return silently. Otherwise, the behaviour is identical to Once this module has been declared in a program, a crontab file can be used to augment the current job list with a call to -@code{read-vixie-file}. +@code{read-vixie-file}. @node Index, , Guile modules, Top @unnumbered Index diff --git a/makefile.am b/makefile.am index 633cf2f..189ce02 100644 --- a/makefile.am +++ b/makefile.am @@ -1,5 +1,6 @@ ## Makefile for the toplevel directory of mcron. ## Copyright (C) 2003 Dale Mellor +## Copyright (C) 2015 Mathieu Lirzin ## # This file is part of GNU mcron. # @@ -31,9 +32,9 @@ CLEANFILES = mcron.c EXTRA_DIST = makefile.ed mcron.c.template BUGS -info_TEXINFOS = mcron.texinfo +info_TEXINFOS = doc/mcron.texi -dist_man_MANS = mcron.1 +dist_man_MANS = doc/mcron.1 bin_PROGRAMS = mcron mcron_SOURCES = mcron.c @@ -79,6 +80,6 @@ uninstall-hook: # Not part of formal package building, but a rule for manual use to get the # elemental man page. Will only work once the mcron program is installed. -mcron.1 : mcron.c - $(HELP2MAN) -n 'a program to run tasks at regular (or not) intervals' \ - ./mcron > mcron.1 +doc/mcron.1: mcron.c + -$(HELP2MAN) -n 'a program to run tasks at regular (or not) intervals' \ + ./mcron > $@ From c43a9173e6e70cf12f3f47a845cc91688877a781 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 20 Apr 2016 01:21:43 +0200 Subject: [PATCH 041/239] maint: Use 'build-aux' directory for auxiliary build tools. * configure.ac (AC_CONFIG_AUX_DIR): Set it to 'build-aux'. * .gitignore: Adapt to it. --- .gitignore | 7 +++++++ configure.ac | 1 + 2 files changed, 8 insertions(+) diff --git a/.gitignore b/.gitignore index 2bedd6e..6aaa315 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,14 @@ INSTALL aclocal.m4 autom4te.cache +/build-aux/compile +/build-aux/depcomp +/build-aux/install-sh +/build-aux/mdate-sh +/build-aux/missing +/build-aux/texinfo.tex compile +config.cache config.log config.scm config.status diff --git a/configure.ac b/configure.ac index fee17fc..6b0fc4c 100644 --- a/configure.ac +++ b/configure.ac @@ -23,6 +23,7 @@ AC_PREREQ(2.61) AC_INIT([mcron], [1.0.8], [dale_mellor@users.sourceforge.net]) +AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE From 754d1d01761922b0c609058607fd854049d7b737 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 1 Jul 2015 01:05:34 +0200 Subject: [PATCH 042/239] maint: Fix package name and bug reports email address. * configure.ac (AC_INIT): Fix package name and bug reports email address. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6b0fc4c..3826bad 100644 --- a/configure.ac +++ b/configure.ac @@ -22,7 +22,7 @@ AC_PREREQ(2.61) -AC_INIT([mcron], [1.0.8], [dale_mellor@users.sourceforge.net]) +AC_INIT([GNU Mcron], [1.0.8], [bug-mcron@gnu.org]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE From 940146bc909d5ee2dd491dbc76d07f2b6f740152 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 7 Jul 2015 11:56:52 +0200 Subject: [PATCH 043/239] doc: Include a copy of the GNU FDL. * doc/fdl.texi: New file. * doc/mcron.texi: Include it. * makefile.am (doc_mcron_TEXINFOS): New variable. --- doc/fdl.texi | 505 +++++++++++++++++++++++++++++++++++++++++++++++++ doc/mcron.texi | 6 + makefile.am | 2 +- 3 files changed, 512 insertions(+), 1 deletion(-) create mode 100644 doc/fdl.texi diff --git a/doc/fdl.texi b/doc/fdl.texi new file mode 100644 index 0000000..9c3bbe5 --- /dev/null +++ b/doc/fdl.texi @@ -0,0 +1,505 @@ +@c The GNU Free Documentation License. +@center Version 1.3, 3 November 2008 + +@c This file is intended to be included within another document, +@c hence no sectioning command or @node. + +@display +Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. +@uref{http://fsf.org/} + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. +@end display + +@enumerate 0 +@item +PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document @dfn{free} in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of ``copyleft'', which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + +@item +APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The ``Document'', below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as ``you''. You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A ``Modified Version'' of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A ``Secondary Section'' is a named appendix or a front-matter section +of the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall +subject (or to related matters) and contains nothing that could fall +directly within that overall subject. (Thus, if the Document is in +part a textbook of mathematics, a Secondary Section may not explain +any mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The ``Invariant Sections'' are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The ``Cover Texts'' are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A ``Transparent'' copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not ``Transparent'' is called ``Opaque''. + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, La@TeX{} input +format, SGML or XML using a publicly available +DTD, and standard-conforming simple HTML, +PostScript or PDF designed for human modification. Examples +of transparent image formats include PNG, XCF and +JPG@. Opaque formats include proprietary formats that can be +read and edited only by proprietary word processors, SGML or +XML for which the DTD and/or processing tools are +not generally available, and the machine-generated HTML, +PostScript or PDF produced by some word processors for +output purposes only. + +The ``Title Page'' means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, ``Title Page'' means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +The ``publisher'' means any person or entity that distributes copies +of the Document to the public. + +A section ``Entitled XYZ'' means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as ``Acknowledgements'', +``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title'' +of such a section when you modify the Document means that it remains a +section ``Entitled XYZ'' according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + +@item +VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + +@item +COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. + +@item +MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +@enumerate A +@item +Use in the Title Page (and on the covers, if any) a title distinct +from that of the Document, and from those of previous versions +(which should, if there were any, be listed in the History section +of the Document). You may use the same title as a previous version +if the original publisher of that version gives permission. + +@item +List on the Title Page, as authors, one or more persons or entities +responsible for authorship of the modifications in the Modified +Version, together with at least five of the principal authors of the +Document (all of its principal authors, if it has fewer than five), +unless they release you from this requirement. + +@item +State on the Title page the name of the publisher of the +Modified Version, as the publisher. + +@item +Preserve all the copyright notices of the Document. + +@item +Add an appropriate copyright notice for your modifications +adjacent to the other copyright notices. + +@item +Include, immediately after the copyright notices, a license notice +giving the public permission to use the Modified Version under the +terms of this License, in the form shown in the Addendum below. + +@item +Preserve in that license notice the full lists of Invariant Sections +and required Cover Texts given in the Document's license notice. + +@item +Include an unaltered copy of this License. + +@item +Preserve the section Entitled ``History'', Preserve its Title, and add +to it an item stating at least the title, year, new authors, and +publisher of the Modified Version as given on the Title Page. If +there is no section Entitled ``History'' in the Document, create one +stating the title, year, authors, and publisher of the Document as +given on its Title Page, then add an item describing the Modified +Version as stated in the previous sentence. + +@item +Preserve the network location, if any, given in the Document for +public access to a Transparent copy of the Document, and likewise +the network locations given in the Document for previous versions +it was based on. These may be placed in the ``History'' section. +You may omit a network location for a work that was published at +least four years before the Document itself, or if the original +publisher of the version it refers to gives permission. + +@item +For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve +the Title of the section, and preserve in the section all the +substance and tone of each of the contributor acknowledgements and/or +dedications given therein. + +@item +Preserve all the Invariant Sections of the Document, +unaltered in their text and in their titles. Section numbers +or the equivalent are not considered part of the section titles. + +@item +Delete any section Entitled ``Endorsements''. Such a section +may not be included in the Modified Version. + +@item +Do not retitle any existing section to be Entitled ``Endorsements'' or +to conflict in title with any Invariant Section. + +@item +Preserve any Warranty Disclaimers. +@end enumerate + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled ``Endorsements'', provided it contains +nothing but endorsements of your Modified Version by various +parties---for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + +@item +COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled ``History'' +in the various original documents, forming one section Entitled +``History''; likewise combine any sections Entitled ``Acknowledgements'', +and any sections Entitled ``Dedications''. You must delete all +sections Entitled ``Endorsements.'' + +@item +COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. + +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. + +@item +AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an ``aggregate'' if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + +@item +TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled ``Acknowledgements'', +``Dedications'', or ``History'', the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + +@item +TERMINATION + +You may not copy, modify, sublicense, or distribute the Document +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense, or distribute it is void, and +will automatically terminate your rights under this License. + +However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally +terminates your license, and (b) permanently, if the copyright holder +fails to notify you of the violation by some reasonable means prior to +60 days after the cessation. + +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, receipt of a copy of some or all of the same material does +not give you any rights to use it. + +@item +FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. See +@uref{http://www.gnu.org/copyleft/}. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License ``or any later version'' applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. If the Document +specifies that a proxy can decide which future versions of this +License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the +Document. + +@item +RELICENSING + +``Massive Multiauthor Collaboration Site'' (or ``MMC Site'') means any +World Wide Web server that publishes copyrightable works and also +provides prominent facilities for anybody to edit those works. A +public wiki that anybody can edit is an example of such a server. A +``Massive Multiauthor Collaboration'' (or ``MMC'') contained in the +site means any set of copyrightable works thus published on the MMC +site. + +``CC-BY-SA'' means the Creative Commons Attribution-Share Alike 3.0 +license published by Creative Commons Corporation, a not-for-profit +corporation with a principal place of business in San Francisco, +California, as well as future copyleft versions of that license +published by that same organization. + +``Incorporate'' means to publish or republish a Document, in whole or +in part, as part of another Document. + +An MMC is ``eligible for relicensing'' if it is licensed under this +License, and if all works that were first published under this License +somewhere other than this MMC, and subsequently incorporated in whole +or in part into the MMC, (1) had no cover texts or invariant sections, +and (2) were thus incorporated prior to November 1, 2008. + +The operator of an MMC Site may republish an MMC contained in the site +under CC-BY-SA on the same site at any time before August 1, 2009, +provided the MMC is eligible for relicensing. + +@end enumerate + +@page +@heading ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + +@smallexample +@group + Copyright (C) @var{year} @var{your name}. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.3 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover + Texts. A copy of the license is included in the section entitled ``GNU + Free Documentation License''. +@end group +@end smallexample + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the ``with@dots{}Texts.''@: line with this: + +@smallexample +@group + with the Invariant Sections being @var{list their titles}, with + the Front-Cover Texts being @var{list}, and with the Back-Cover Texts + being @var{list}. +@end group +@end smallexample + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. + +@c Local Variables: +@c ispell-local-pdict: "ispell-dict" +@c End: diff --git a/doc/mcron.texi b/doc/mcron.texi index cb97a06..27cd1b7 100644 --- a/doc/mcron.texi +++ b/doc/mcron.texi @@ -63,6 +63,7 @@ running jobs at scheduled times. * Syntax:: All the possibilities for configuring cron jobs. * Invoking:: What happens when you run the mcron command. * Guile modules:: Incorporating mcron into another Guile program. +* GNU Free Documentation License:: The license of this manual. * Index:: The complete index. @detailmenu @@ -1329,6 +1330,11 @@ Once this module has been declared in a program, a crontab file can be used to augment the current job list with a call to @code{read-vixie-file}. +@node GNU Free Documentation License +@appendix GNU Free Documentation License + +@include fdl.texi + @node Index, , Guile modules, Top @unnumbered Index diff --git a/makefile.am b/makefile.am index 189ce02..431190c 100644 --- a/makefile.am +++ b/makefile.am @@ -33,7 +33,7 @@ CLEANFILES = mcron.c EXTRA_DIST = makefile.ed mcron.c.template BUGS info_TEXINFOS = doc/mcron.texi - +doc_mcron_TEXINFOS = doc/fdl.texi dist_man_MANS = doc/mcron.1 bin_PROGRAMS = mcron From 607d5e060df87dccf3d8fd478250c3e8832f105b Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 21 Jul 2015 00:01:45 +0200 Subject: [PATCH 044/239] build: Add package variables. * scm/mcron/config.scm.in (config-package-name) (configure-package-version, configure-package-url): New variables. --- scm/mcron/config.scm.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scm/mcron/config.scm.in b/scm/mcron/config.scm.in index 6a0a85d..db2bc32 100644 --- a/scm/mcron/config.scm.in +++ b/scm/mcron/config.scm.in @@ -1,5 +1,6 @@ ;; -*-scheme-*- +;; Copyright (C) 2015 Mathieu Lirzin ;; Copyright (C) 2003 Dale Mellor ;; ;; This file is part of GNU mcron. @@ -23,8 +24,11 @@ (define-module (mcron config)) (define-public config-debug @CONFIG_DEBUG@) +(define-public config-package-name "@PACKAGE_NAME@") +(define-public config-package-version "@PACKAGE_VERSION@") (define-public config-package-string "@PACKAGE_STRING@") (define-public config-package-bugreport "@PACKAGE_BUGREPORT@") +(define-public config-package-url "@PACKAGE_URL@") (define-public config-sendmail "@SENDMAIL@") (define-public config-spool-dir "@CONFIG_SPOOL_DIR@") From 2dd8fa9d8f4cc23f4a02a41c2b7898e5c8143e54 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 21 Jul 2015 00:53:46 +0200 Subject: [PATCH 045/239] main: Add 'show-version' procedure. * scm/mcron/main.scm (show-version): New procedure. --- scm/mcron/main.scm | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index 36adef9..db321cf 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -1,3 +1,4 @@ +;; Copyright (C) 2015, 2016 Mathieu Lirzin ;; Copyright (C) 2003, 2012 Dale Mellor ;; ;; This file is part of GNU mcron. @@ -122,25 +123,25 @@ (lambda (key func fmt args . rest) (mcron-error 1 (apply format (append (list #f fmt) args)))))) -;; If the user asked for the version of this program, give it to him and get +(define* (show-version #:optional (command command-name)) + "Display version information for COMMAND and quit." + (let* ((name config-package-name) + (short-name (cadr (string-split name #\space))) + (version config-package-version)) + (simple-format #t "~a (~a) ~a\n +Copyright (C) 2015 the ~a authors.\n +License GPLv3+: GNU GPL version 3 or later \n +This is free software: you are free to change and redistribute it.\n +There is NO WARRANTY, to the extent permitted by law.\n" + command name version short-name) + (quit))) + +(when (option-ref options 'version #f) + (show-version)) + +;; If the user asked for the help text of this program, give it to him and get ;; out. -(if (option-ref options 'version #f) - (begin - (display (string-append "\n -" command-name " (" config-package-string ")\n -Written by Dale Mellor\n -\n -Copyright (C) 2003, 2006, 2014 Dale Mellor\n -This is free software; see the source for copying conditions. There is NO\n -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n -")) - (quit))) - - - -;; Likewise if the user requested the help text. - (if (option-ref options 'help #f) (begin (display (string-append " From 8f136b3d67966a1a72cadd74fdad850e24797a4c Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 21 Jul 2015 16:23:52 +0200 Subject: [PATCH 046/239] main: Add 'show-package-information' procedure. * scm/mcron/main.scm (show-package-information): New procedure. --- scm/mcron/main.scm | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index db321cf..f5e9e3e 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -139,6 +139,15 @@ There is NO WARRANTY, to the extent permitted by law.\n" (when (option-ref options 'version #f) (show-version)) +(define (show-package-information) + "Display where to get help and send bug reports." + (simple-format #t "\nReport bugs to: ~a.\n +~a home page: <~a>\n +General help using GNU software: \n" + config-package-bugreport + config-package-name + config-package-url)) + ;; If the user asked for the help text of this program, give it to him and get ;; out. @@ -181,11 +190,9 @@ reading all the information in the users' crontabs and in /etc/crontab.\n " -l (list user's crontab)\n" " -r (delete user's crontab)\n")) - (else "rubbish")) - -"\n\n -Report bugs to " config-package-bugreport ".\n -")) + (else "rubbish")))) + (newline) + (show-package-information) (quit))) From cdd26d5b00a7472e7a235b473e5b3eeab5f905b9 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 21 Jul 2015 17:23:32 +0200 Subject: [PATCH 047/239] main: Add 'show-help' procedure. * scm/mcron/main.scm (show-help): New procedure. --- scm/mcron/main.scm | 50 ++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index f5e9e3e..5f48379 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -148,17 +148,13 @@ General help using GNU software: \n" config-package-name config-package-url)) -;; If the user asked for the help text of this program, give it to him and get -;; out. - -(if (option-ref options 'help #f) - (begin - (display (string-append " -Usage: " (car (command-line)) -(case command-type - - ((mcron) -" [OPTIONS] [FILES]\n +(define* (show-help #:optional (command command-name)) + "Display informations of usage for COMMAND and quit." + (simple-format #t "Usage: ~a" command) + (display + (case command-type + ((mcron) + " [OPTIONS] [FILES]\n Run an mcron process according to the specifications in the FILES (`-' for\n standard input), or use all the files in ~/.config/cron (or the \n deprecated ~/.cron) with .guile or .vixie extensions.\n @@ -170,9 +166,8 @@ deprecated ~/.cron) with .guile or .vixie extensions.\n and run as a daemon process\n -i, --stdin=(guile|vixie) Format of data passed as standard input or\n file arguments (default guile)") - - ((cron) -" [OPTIONS]\n + ((cron) + " [OPTIONS]\n Unless an option is specified, run a cron daemon as a detached process, \n reading all the information in the users' crontabs and in /etc/crontab.\n \n @@ -181,21 +176,20 @@ reading all the information in the users' crontabs and in /etc/crontab.\n -sN, --schedule[=]N Display the next N jobs that 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" - " " (car (command-line)) " [-u user] { -e | -l | -r }\n" - " (default operation is replace, per 1003.2)\n" - " -e (edit user's crontab)\n" - " -l (list user's crontab)\n" - " -r (delete user's crontab)\n")) - - (else "rubbish")))) - (newline) - (show-package-information) - (quit))) - + ((crontab) + " [-u user] file\n + crontab [-u user] { -e | -l | -r }\n + (default operation is replace, per 1003.2)\n + -e (edit user's crontab)\n + -l (list user's crontab)\n + -r (delete user's crontab") + (else "\nrubbish"))) + (newline) + (show-package-information) + (quit)) +(when (option-ref options 'help #f) + (show-help)) ;; This is called from the C front-end whenever a terminal signal is ;; received. We remove the /var/run/cron.pid file so that crontab and other From f0feb586b711c6085d9b701197756840f7f9aa5d Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 11 Aug 2015 15:36:01 +0200 Subject: [PATCH 048/239] maint: Augment TODO. * TODO : Add items. --- TODO | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/TODO b/TODO index 9ed8bca..b43f233 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,6 @@ GNU mcron --- TODO -*-text-*- + Copyright (C) 2015, 2016 Mathieu Lirzin Copyright (C) 2003, 2005, 2006, 2014 Dale Mellor Copying and distribution of this file, with or without modification, @@ -19,6 +20,14 @@ Maybe in the near future... core or other users' files up. Then allow scheme code in the system crontabs. + * Make mcron behavior not depend on the name used to invoke it, to conform + to GNU Coding Standards. + + * Provide a test suite using SRFI-64 API. + . + + * Internationalize Mcron using GNU Gettext and ask the Translation + Project to handle the localization. There are no plans to actually do the following any time soon... From ee280d4efc49b54658073aac945a22f81508c086 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 27 Sep 2015 20:10:24 +0200 Subject: [PATCH 049/239] build: Remove MAINTAINERCLEANFILES variable. * makefile.am (MAINTAINERCLEANFILES): Delete unneeded variable. Using 'git clean -xdf' is more reliable than 'make maintainer-clean' --- makefile.am | 4 ---- 1 file changed, 4 deletions(-) diff --git a/makefile.am b/makefile.am index 431190c..da26a89 100644 --- a/makefile.am +++ b/makefile.am @@ -24,10 +24,6 @@ SUBDIRS = scm/mcron . ED = @ED@ # !!!! Are these needed? CP = @CP@ -MAINTAINERCLEANFILES = configure makefile makefile.in config.guess config.sub \ - install-sh missing texinfo.tex INSTALL \ - aclocal.m4 compile depcomp mcron.1 - CLEANFILES = mcron.c EXTRA_DIST = makefile.ed mcron.c.template BUGS From 7ed303705c17b127cc224ee1ddecc53a931d65e5 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 22 Jul 2015 01:00:45 +0200 Subject: [PATCH 050/239] build: Generate 'ChangeLog' upon 'make dist'. * ChangeLog: Rename to ... * ChangeLog.old: ... this. * ChangeLog: New file. * Makefile.am (gen_start_date): New variable. (gen-ChangeLog, dist-hook): New targets. (EXTRA_DIST): Add 'ChangeLog.old'. * build-aux/gitlog-to-changelog: New file, from Gnulib. --- ChangeLog | 167 +----------- ChangeLog.old | 147 ++++++++++ build-aux/gitlog-to-changelog | 492 ++++++++++++++++++++++++++++++++++ makefile.am | 17 +- 4 files changed, 658 insertions(+), 165 deletions(-) create mode 100644 ChangeLog.old create mode 100755 build-aux/gitlog-to-changelog diff --git a/ChangeLog b/ChangeLog index 15e01c0..fe5459d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,165 +1,4 @@ -2014-05-25 Dale Mellor +Normally a ChangeLog is generated at "make dist" time and available in +source tarballs. - * Juggled build infrastructure so that we can make the minimal man - page in the proper autotools way. - - * configure.ac: version to 1.0.8. - - -2014-04-28 Dale Mellor - - * We now run against, and require, guile-2.0. - - * configure.ac: version to 1.0.7. - - -2012-02-04 Dale Mellor - - * main.scm: added search for initial files in - $XDG_CONFIG_HOME/cron directory, defaulting to ~/.config/cron if - the environment variable is not set) as well as in ~/.cron - directory (this is in line with the current FreeDesktop.org - standards). - - -2010-06-13 Dale Mellor - - * configure.ac: added --enable-no-vixie-clobber argument to - configure so that the root user can avoid overwriting a legacy - cron installation. - - * mcron.1: added simple, minimal man page using help2man (the - texinfo file is still the primary documentation source). - - * makefile.am: replaced use of mkinstalldirs with install; the - former is not supplied with the latest automake (1.11). - - -2008-02-21 Dale Mellor - - * ALL FILES: Replaced version 2 GPL notices with version 3 ones. - - * makefile.am: Do not remove COPYING file with make - maintainer-clean; if you do it will eventually get replaced with - the old version 2 GPL by a subsequent automake. - - * configure.ac: Bumped version to 1.0.4. - - -2008-01-25 Dale Mellor - - * main.scm (command-type): Files which are listed on the command - line are assumed to be guile configurations if they do not end in - .guile or .vixie (previously they were silently ignored). - - * main.scm: Argument to --schedule is no longer optional (the - options system goes really screwy with optional values, usually - pulling the first non-option argument as a value if one was not - intended!) - - * makefile.am: Moved target-specific CFLAGS and LDFLAGS to global - AM_* variables, to remove problem with automake requiring - AM_PROGS_CC_C_O in configure.ac (!) - - * Version is currently at 1.0.3. - - -2005-09-02 Dale Mellor - - * makefile.am, mcron.c.template (main): Modified install-exec-hook - so that a proper installation of a Vixie-compatible cron only - takes place if we are root - otherwise only mcron is installed as - a user-owned program. The guile modules are now installed under - mcron's shared data directory, not guile's global directories. - - * mcron-core.scm: Removed job:advance-time, put the code inline - where it was called, and changed the instance in the main loop to - compute the new time based on the current-time, rather than the - previous job time (this makes things behave more reasonably when a - laptop awakes from suspend mode). - - * Bumped version to 1.0.2. - - -2004-05-15 Dale Mellor - - * Modified all auxiliary files to reflect that the package is now - properly homed at www.gnu.org. - - * Bumped version to 1.0.1. - - -2003-12-11 Dale Mellor - - * Modified all auxiliary files to reflect that we are now a GNU - package. - - * Bumped version to 1.0.0. - - -2003-12-07 Dale Mellor - - * configure.ac: Added switches for files and directories used by - mcron: --spool-dir, --socket-file, --allow-file, --deny-file, - --pid-file and --tmp-dir. All the code has been modified to use - these configure options (including the source for the texinfo - manual). - - -2003-12-05 Dale Mellor - - * configure.ac: Added test for guile version >= 1.6.4. - - * bumped version to 0.99.4. - - -2003-08-03 Dale Mellor - - * Third cut, fully functional, modular, production quality, still - needs testing... - - * Pulled all functionality into modules, so it can be incorporated - into other programs. - - * Bumped version to 0.99.3. - - -2003-07-20 Dale Mellor - - * 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. - - -2003-06-28 Dale Mellor - - * First cut, fully functional, production quality code, just needs - testing... - - * Broken/incomplete Guile prevents vixie compatibility from - working - this has been disabled by default in the configuration. - - * Version set at 0.99.1 - - - - - - -________________________________________________________________________________ -Copyright (C) 2003, 2005, 2006, 2014 Dale Mellor - -Copying and distribution of this file, with or without modification, -are permitted in any medium without royalty provided the copyright -notice and this notice are preserved. +If not, see the Git commit log at . diff --git a/ChangeLog.old b/ChangeLog.old new file mode 100644 index 0000000..09c4147 --- /dev/null +++ b/ChangeLog.old @@ -0,0 +1,147 @@ +2014-05-25 Dale Mellor + + * Juggled build infrastructure so that we can make the minimal man + page in the proper autotools way. + + * configure.ac: version to 1.0.8. + +2014-04-28 Dale Mellor + + * We now run against, and require, guile-2.0. + + * configure.ac: version to 1.0.7. + +2012-02-04 Dale Mellor + + * main.scm: added search for initial files in + $XDG_CONFIG_HOME/cron directory, defaulting to ~/.config/cron if + the environment variable is not set) as well as in ~/.cron + directory (this is in line with the current FreeDesktop.org + standards). + +2010-06-13 Dale Mellor + + * configure.ac: added --enable-no-vixie-clobber argument to + configure so that the root user can avoid overwriting a legacy + cron installation. + + * mcron.1: added simple, minimal man page using help2man (the + texinfo file is still the primary documentation source). + + * makefile.am: replaced use of mkinstalldirs with install; the + former is not supplied with the latest automake (1.11). + +2008-02-21 Dale Mellor + + * ALL FILES: Replaced version 2 GPL notices with version 3 ones. + + * makefile.am: Do not remove COPYING file with make + maintainer-clean; if you do it will eventually get replaced with + the old version 2 GPL by a subsequent automake. + + * configure.ac: Bumped version to 1.0.4. + +2008-01-25 Dale Mellor + + * main.scm (command-type): Files which are listed on the command + line are assumed to be guile configurations if they do not end in + .guile or .vixie (previously they were silently ignored). + + * main.scm: Argument to --schedule is no longer optional (the + options system goes really screwy with optional values, usually + pulling the first non-option argument as a value if one was not + intended!) + + * makefile.am: Moved target-specific CFLAGS and LDFLAGS to global + AM_* variables, to remove problem with automake requiring + AM_PROGS_CC_C_O in configure.ac (!) + + * Version is currently at 1.0.3. + +2005-09-02 Dale Mellor + + * makefile.am, mcron.c.template (main): Modified install-exec-hook + so that a proper installation of a Vixie-compatible cron only + takes place if we are root - otherwise only mcron is installed as + a user-owned program. The guile modules are now installed under + mcron's shared data directory, not guile's global directories. + + * mcron-core.scm: Removed job:advance-time, put the code inline + where it was called, and changed the instance in the main loop to + compute the new time based on the current-time, rather than the + previous job time (this makes things behave more reasonably when a + laptop awakes from suspend mode). + + * Bumped version to 1.0.2. + +2004-05-15 Dale Mellor + + * Modified all auxiliary files to reflect that the package is now + properly homed at www.gnu.org. + + * Bumped version to 1.0.1. + +2003-12-11 Dale Mellor + + * Modified all auxiliary files to reflect that we are now a GNU + package. + + * Bumped version to 1.0.0. + +2003-12-07 Dale Mellor + + * configure.ac: Added switches for files and directories used by + mcron: --spool-dir, --socket-file, --allow-file, --deny-file, + --pid-file and --tmp-dir. All the code has been modified to use + these configure options (including the source for the texinfo + manual). + +2003-12-05 Dale Mellor + + * configure.ac: Added test for guile version >= 1.6.4. + + * bumped version to 0.99.4. + +2003-08-03 Dale Mellor + + * Third cut, fully functional, modular, production quality, still + needs testing... + + * Pulled all functionality into modules, so it can be incorporated + into other programs. + + * Bumped version to 0.99.3. + +2003-07-20 Dale Mellor + + * 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. + +2003-06-28 Dale Mellor + + * First cut, fully functional, production quality code, just needs + testing... + + * Broken/incomplete Guile prevents vixie compatibility from + working - this has been disabled by default in the configuration. + + * Version set at 0.99.1 + +________________________________________________________________________________ +Copyright (C) 2003, 2005, 2006, 2014, 2015 Dale Mellor + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/build-aux/gitlog-to-changelog b/build-aux/gitlog-to-changelog new file mode 100755 index 0000000..8f38318 --- /dev/null +++ b/build-aux/gitlog-to-changelog @@ -0,0 +1,492 @@ +eval '(exit $?0)' && eval 'exec perl -wS "$0" ${1+"$@"}' + & eval 'exec perl -wS "$0" $argv:q' + if 0; +# Convert git log output to ChangeLog format. + +my $VERSION = '2015-07-21 22:45'; # UTC +# The definition above must lie within the first 8 lines in order +# for the Emacs time-stamp write hook (at end) to update it. +# If you change this file with Emacs, please let the write hook +# do its job. Otherwise, update this string manually. + +# Copyright (C) 2008-2015 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Written by Jim Meyering + +use strict; +use warnings; +use Getopt::Long; +use POSIX qw(strftime); + +(my $ME = $0) =~ s|.*/||; + +# use File::Coda; # http://meyering.net/code/Coda/ +END { + defined fileno STDOUT or return; + close STDOUT and return; + warn "$ME: failed to close standard output: $!\n"; + $? ||= 1; +} + +sub usage ($) +{ + my ($exit_code) = @_; + my $STREAM = ($exit_code == 0 ? *STDOUT : *STDERR); + if ($exit_code != 0) + { + print $STREAM "Try '$ME --help' for more information.\n"; + } + else + { + print $STREAM < ChangeLog + $ME -- -n 5 foo > last-5-commits-to-branch-foo + +SPECIAL SYNTAX: + +The following types of strings are interpreted specially when they appear +at the beginning of a log message line. They are not copied to the output. + + Copyright-paperwork-exempt: Yes + Append the "(tiny change)" notation to the usual "date name email" + ChangeLog header to mark a change that does not require a copyright + assignment. + Co-authored-by: Joe User + List the specified name and email address on a second + ChangeLog header, denoting a co-author. + Signed-off-by: Joe User + These lines are simply elided. + +In a FILE specified via --amend, comment lines (starting with "#") are ignored. +FILE must consist of pairs where SHA is a 40-byte SHA1 (alone on +a line) referring to a commit in the current project, and CODE refers to one +or more consecutive lines of Perl code. Pairs must be separated by one or +more blank line. + +Here is sample input for use with --amend=FILE, from coreutils: + +3a169f4c5d9159283548178668d2fae6fced3030 +# fix typo in title: +s/all tile types/all file types/ + +1379ed974f1fa39b12e2ffab18b3f7a607082202 +# Due to a bug in vc-dwim, I mis-attributed a patch by Paul to myself. +# Change the author to be Paul. Note the escaped "@": +s,Jim .*>,Paul Eggert , + +EOF + } + exit $exit_code; +} + +# If the string $S is a well-behaved file name, simply return it. +# If it contains white space, quotes, etc., quote it, and return the new string. +sub shell_quote($) +{ + my ($s) = @_; + if ($s =~ m![^\w+/.,-]!) + { + # Convert each single quote to '\'' + $s =~ s/\'/\'\\\'\'/g; + # Then single quote the string. + $s = "'$s'"; + } + return $s; +} + +sub quoted_cmd(@) +{ + return join (' ', map {shell_quote $_} @_); +} + +# Parse file F. +# Comment lines (starting with "#") are ignored. +# F must consist of pairs where SHA is a 40-byte SHA1 +# (alone on a line) referring to a commit in the current project, and +# CODE refers to one or more consecutive lines of Perl code. +# Pairs must be separated by one or more blank line. +sub parse_amend_file($) +{ + my ($f) = @_; + + open F, '<', $f + or die "$ME: $f: failed to open for reading: $!\n"; + + my $fail; + my $h = {}; + my $in_code = 0; + my $sha; + while (defined (my $line = )) + { + $line =~ /^\#/ + and next; + chomp $line; + $line eq '' + and $in_code = 0, next; + + if (!$in_code) + { + $line =~ /^([0-9a-fA-F]{40})$/ + or (warn "$ME: $f:$.: invalid line; expected an SHA1\n"), + $fail = 1, next; + $sha = lc $1; + $in_code = 1; + exists $h->{$sha} + and (warn "$ME: $f:$.: duplicate SHA1\n"), + $fail = 1, next; + } + else + { + $h->{$sha} ||= ''; + $h->{$sha} .= "$line\n"; + } + } + close F; + + $fail + and exit 1; + + return $h; +} + +# git_dir_option $SRCDIR +# +# From $SRCDIR, the --git-dir option to pass to git (none if $SRCDIR +# is undef). Return as a list (0 or 1 element). +sub git_dir_option($) +{ + my ($srcdir) = @_; + my @res = (); + if (defined $srcdir) + { + my $qdir = shell_quote $srcdir; + my $cmd = "cd $qdir && git rev-parse --show-toplevel"; + my $qcmd = shell_quote $cmd; + my $git_dir = qx($cmd); + defined $git_dir + or die "$ME: cannot run $qcmd: $!\n"; + $? == 0 + or die "$ME: $qcmd had unexpected exit code or signal ($?)\n"; + chomp $git_dir; + push @res, "--git-dir=$git_dir/.git"; + } + @res; +} + +{ + my $since_date; + my $until_date; + my $format_string = '%s%n%b%n'; + my $amend_file; + my $append_dot = 0; + my $cluster = 1; + my $ignore_matching; + my $ignore_line; + my $strip_tab = 0; + my $strip_cherry_pick = 0; + my $srcdir; + GetOptions + ( + help => sub { usage 0 }, + version => sub { print "$ME version $VERSION\n"; exit }, + 'since=s' => \$since_date, + 'until=s' => \$until_date, + 'format=s' => \$format_string, + 'amend=s' => \$amend_file, + 'append-dot' => \$append_dot, + 'cluster!' => \$cluster, + 'ignore-matching=s' => \$ignore_matching, + 'ignore-line=s' => \$ignore_line, + 'strip-tab' => \$strip_tab, + 'strip-cherry-pick' => \$strip_cherry_pick, + 'srcdir=s' => \$srcdir, + ) or usage 1; + + defined $since_date + and unshift @ARGV, "--since=$since_date"; + defined $until_date + and unshift @ARGV, "--until=$until_date"; + + # This is a hash that maps an SHA1 to perl code (i.e., s/old/new/) + # that makes a correction in the log or attribution of that commit. + my $amend_code = defined $amend_file ? parse_amend_file $amend_file : {}; + + my @cmd = ('git', + git_dir_option $srcdir, + qw(log --log-size), + '--pretty=format:%H:%ct %an <%ae>%n%n'.$format_string, @ARGV); + open PIPE, '-|', @cmd + or die ("$ME: failed to run '". quoted_cmd (@cmd) ."': $!\n" + . "(Is your Git too old? Version 1.5.1 or later is required.)\n"); + + my $prev_multi_paragraph; + my $prev_date_line = ''; + my @prev_coauthors = (); + my @skipshas = (); + while (1) + { + defined (my $in = ) + or last; + $in =~ /^log size (\d+)$/ + or die "$ME:$.: Invalid line (expected log size):\n$in"; + my $log_nbytes = $1; + + my $log; + my $n_read = read PIPE, $log, $log_nbytes; + $n_read == $log_nbytes + or die "$ME:$.: unexpected EOF\n"; + + # Extract leading hash. + my ($sha, $rest) = split ':', $log, 2; + defined $sha + or die "$ME:$.: malformed log entry\n"; + $sha =~ /^[0-9a-fA-F]{40}$/ + or die "$ME:$.: invalid SHA1: $sha\n"; + + my $skipflag = 0; + if (@skipshas) + { + foreach(@skipshas) + { + if ($sha =~ /^$_/) + { + $skipflag = 1; + ## Perhaps only warn if a pattern matches more than once? + warn "$ME: warning: skipping $sha due to $_\n"; + last; + } + } + } + + # If this commit's log requires any transformation, do it now. + my $code = $amend_code->{$sha}; + if (defined $code) + { + eval 'use Safe'; + my $s = new Safe; + # Put the unpreprocessed entry into "$_". + $_ = $rest; + + # Let $code operate on it, safely. + my $r = $s->reval("$code") + or die "$ME:$.:$sha: failed to eval \"$code\":\n$@\n"; + + # Note that we've used this entry. + delete $amend_code->{$sha}; + + # Update $rest upon success. + $rest = $_; + } + + # Remove lines inserted by "git cherry-pick". + if ($strip_cherry_pick) + { + $rest =~ s/^\s*Conflicts:\n.*//sm; + $rest =~ s/^\s*\(cherry picked from commit [\da-f]+\)\n//m; + } + + my @line = split /\s*\n/, $rest; + my $author_line = shift @line; + defined $author_line + or die "$ME:$.: unexpected EOF\n"; + $author_line =~ /^(\d+) (.*>)$/ + or die "$ME:$.: Invalid line " + . "(expected date/author/email):\n$author_line\n"; + + # Format 'Copyright-paperwork-exempt: Yes' as a standard ChangeLog + # `(tiny change)' annotation. + my $tiny = (grep (/^(?:Copyright-paperwork-exempt|Tiny-change):\s+[Yy]es$/, @line) + ? ' (tiny change)' : ''); + + my $date_line = sprintf "%s %s$tiny\n", + strftime ("%Y-%m-%d", localtime ($1)), $2; + + my @coauthors = grep /^Co-authored-by:.*$/, @line; + # Omit meta-data lines we've already interpreted. + @line = grep !/^(?:Signed-off-by:[ ].*>$ + |Co-authored-by:[ ] + |Copyright-paperwork-exempt:[ ] + |Tiny-change:[ ] + )/x, @line; + + # Remove leading and trailing blank lines. + if (@line) + { + while ($line[0] =~ /^\s*$/) { shift @line; } + while ($line[$#line] =~ /^\s*$/) { pop @line; } + } + + # Handle Emacs gitmerge.el "skipped" commits. + # Yes, this should be controlled by an option. So sue me. + if ( grep /^(; )?Merge from /, @line ) + { + my $found = 0; + foreach (@line) + { + if (grep /^The following commit.*skipped:$/, $_) + { + $found = 1; + ## Reset at each merge to reduce chance of false matches. + @skipshas = (); + next; + } + if ($found && $_ =~ /^([0-9a-fA-F]{7,}) [^ ]/) + { + push ( @skipshas, $1 ); + } + } + } + + # Ignore commits that match the --ignore-matching pattern, if specified. + if (! ($skipflag || (defined $ignore_matching + && @line && $line[0] =~ /$ignore_matching/))) + { + if (defined $ignore_line && @line) + { + @line = grep ! /$ignore_line/, @line; + while ($line[$#line] =~ /^\s*$/) { pop @line; } + } + + # Record whether there are two or more paragraphs. + my $multi_paragraph = grep /^\s*$/, @line; + + # Format 'Co-authored-by: A U Thor ' lines in + # standard multi-author ChangeLog format. + for (@coauthors) + { + s/^Co-authored-by:\s*/\t /; + s/\s*/ + or warn "$ME: warning: missing email address for " + . substr ($_, 5) . "\n"; + } + + # If clustering of commit messages has been disabled, if this header + # would be different from the previous date/name/etc. header, + # or if this or the previous entry consists of two or more paragraphs, + # then print the header. + if ( ! $cluster + || $date_line ne $prev_date_line + || "@coauthors" ne "@prev_coauthors" + || $multi_paragraph + || $prev_multi_paragraph) + { + $prev_date_line eq '' + or print "\n"; + print $date_line; + @coauthors + and print join ("\n", @coauthors), "\n"; + } + $prev_date_line = $date_line; + @prev_coauthors = @coauthors; + $prev_multi_paragraph = $multi_paragraph; + + # If there were any lines + if (@line == 0) + { + warn "$ME: warning: empty commit message:\n $date_line\n"; + } + else + { + if ($append_dot) + { + # If the first line of the message has enough room, then + if (length $line[0] < 72) + { + # append a dot if there is no other punctuation or blank + # at the end. + $line[0] =~ /[[:punct:]\s]$/ + or $line[0] .= '.'; + } + } + + # Remove one additional leading TAB from each line. + $strip_tab + and map { s/^\t// } @line; + + # Prefix each non-empty line with a TAB. + @line = map { length $_ ? "\t$_" : '' } @line; + + print "\n", join ("\n", @line), "\n"; + } + } + + defined ($in = ) + or last; + $in ne "\n" + and die "$ME:$.: unexpected line:\n$in"; + } + + close PIPE + or die "$ME: error closing pipe from " . quoted_cmd (@cmd) . "\n"; + # FIXME-someday: include $PROCESS_STATUS in the diagnostic + + # Complain about any unused entry in the --amend=F specified file. + my $fail = 0; + foreach my $sha (keys %$amend_code) + { + warn "$ME:$amend_file: unused entry: $sha\n"; + $fail = 1; + } + + exit $fail; +} + +# Local Variables: +# mode: perl +# indent-tabs-mode: nil +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "my $VERSION = '" +# time-stamp-format: "%:y-%02m-%02d %02H:%02M" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "'; # UTC" +# End: diff --git a/makefile.am b/makefile.am index da26a89..61fbe56 100644 --- a/makefile.am +++ b/makefile.am @@ -26,7 +26,7 @@ CP = @CP@ CLEANFILES = mcron.c -EXTRA_DIST = makefile.ed mcron.c.template BUGS +EXTRA_DIST = makefile.ed mcron.c.template BUGS ChangeLog.old info_TEXINFOS = doc/mcron.texi doc_mcron_TEXINFOS = doc/fdl.texi @@ -46,6 +46,21 @@ mcron.c : scm/mcron/main.scm scm/mcron/crontab.scm makefile.ed mcron.c.template @$(ED) < makefile.ed > /dev/null 2>&1 @rm -f mcron.escaped.scm > /dev/null 2>&1 +dist-hook: gen-ChangeLog + +gen_start_date = 2015-06-26 +.PHONY: gen-ChangeLog +gen-ChangeLog: + $(AM_V_GEN)if test -d $(srcdir)/.git; then \ + log_fix="$(srcdir)/build-aux/git-log-fix"; \ + test -e "$$log_fix" \ + && amend_git_log="--amend=$$log_fix" \ + || amend_git_log=; \ + $(top_srcdir)/build-aux/gitlog-to-changelog \ + $$amend_git_log --since=$(gen_start_date) > $(distdir)/cl-t && \ + { rm -f $(distdir)/ChangeLog && \ + mv $(distdir)/cl-t $(distdir)/ChangeLog; } \ + fi #full program prefix fpp = $(DESTDIR)$(bindir)/@real_program_prefix@ From f835793336020212b03232486aa5f76b9953a632 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 12 Aug 2015 16:02:58 +0200 Subject: [PATCH 051/239] main: Import the modules all together. * scm/mcron/main.scm: Gather module imports. --- scm/mcron/main.scm | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index 5f48379..ddd7619 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -29,12 +29,16 @@ ;; (l0ad "crontab.scm") (sic) is inlined by the makefile. All other ;; functionality comes through modules in .../share/guile/site/mcron/*.scm. +(use-modules (ice-9 getopt-long) + (ice-9 rdelim) + (ice-9 regex) + (mcron config) + (mcron core) + (mcron job-specifier) + (mcron vixie-specification) + (srfi srfi-2)) - -;; Pull in some constants set by the builder (via autoconf) at configuration -;; time. Turn debugging on if indicated. - -(use-modules (mcron config)) +;; Turn debugging on if indicated. (if config-debug (begin (debug-enable 'debug) (debug-enable 'backtrace))) @@ -44,8 +48,6 @@ ;; backwards for the first non-alphabetic character. This allows names like ;; in.cron to be accepted as an invocation of the cron command. -(use-modules (ice-9 regex) (ice-9 rdelim)) - (define command-name (match:substring (regexp-exec (make-regexp "[[:alpha:]]*$") (car (command-line))))) @@ -93,8 +95,6 @@ ;; all the others, with the --help and --version options common to all the ;; personalities. -(use-modules (ice-9 getopt-long)) - (define options (catch 'misc-error @@ -234,16 +234,6 @@ reading all the information in the users' crontabs and in /etc/crontab.\n (c-set-cron-signals))) - -;; Define the functions available to the configuration files. While we're here, -;; we'll get the core loaded as well. - -(use-modules (mcron core) - (mcron job-specifier) - (mcron vixie-specification)) - - - ;; Procedure to slurp the standard input into a string. (define (stdin->string) @@ -349,8 +339,6 @@ reading all the information in the users' crontabs and in /etc/crontab.\n ;; operation, but we leave it to the permissions on the /var/cron/tabs directory ;; to enforce this. -(use-modules (srfi srfi-2)) ;; For and-let*. - (define (process-files-in-system-directory) (catch #t (lambda () From 36161428fabfdfa58518739ebcb11416ed920884 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 12 Aug 2015 17:20:51 +0200 Subject: [PATCH 052/239] main: Use 'when' and 'unless' special forms. * scm/mcron/main.scm: Use 'when' and 'unless' special forms. --- scm/mcron/main.scm | 117 ++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 60 deletions(-) diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index ddd7619..39dbe38 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -39,8 +39,9 @@ (srfi srfi-2)) ;; Turn debugging on if indicated. -(if config-debug (begin (debug-enable 'debug) - (debug-enable 'backtrace))) +(when config-debug + (debug-enable 'debug) + (debug-enable 'backtrace)) @@ -62,8 +63,8 @@ (lambda () (for-each display (append (list command-name ": ") rest)) (newline))) - (if (and exit-code (not (eq? exit-code 0))) - (primitive-exit exit-code))) + (when (and exit-code (not (eq? exit-code 0))) + (primitive-exit exit-code))) @@ -215,23 +216,22 @@ reading all the information in the users' crontabs and in /etc/crontab.\n ;; be filled in properly later when we have forked our daemon process (but not ;; done if we are only viewing the schedules). -(if (eq? command-type 'cron) - (begin - (if (not (eqv? (getuid) 0)) - (mcron-error 16 - "This program must be run by the root user (and should " - "have been installed as such).")) - (if (access? config-pid-file F_OK) - (mcron-error 1 - "A cron daemon is already running.\n" - " (If you are sure this is not true, remove the file\n" - " " - config-pid-file - ".)")) - (if (not (option-ref options 'schedule #f)) - (with-output-to-file config-pid-file noop)) - (setenv "MAILTO" #f) - (c-set-cron-signals))) +(when (eq? command-type 'cron) + (unless (eqv? (getuid) 0) + (mcron-error 16 + "This program must be run by the root user (and should " + "have been installed as such).")) + (when (access? config-pid-file F_OK) + (mcron-error 1 + "A cron daemon is already running.\n" + " (If you are sure this is not true, remove the file\n" + " " + config-pid-file + ".)")) + (unless (option-ref options 'schedule #f) + (with-output-to-file config-pid-file noop)) + (setenv "MAILTO" #f) + (c-set-cron-signals)) ;; Procedure to slurp the standard input into a string. @@ -248,10 +248,9 @@ reading all the information in the users' crontabs and in /etc/crontab.\n ;; files. If the user requested the crontab personality, we load and run the ;; code here and then get out. -(if (eq? command-type 'crontab) - (begin - (load "crontab.scm") - (quit))) +(when (eq? command-type 'crontab) + (load "crontab.scm") + (quit)) @@ -310,10 +309,10 @@ reading all the information in the users' crontabs and in /etc/crontab.\n (string-append (or (getenv "XDG_CONFIG_HOME") (string-append home-directory "/.config")) "/cron"))) - (if (eq? 2 errors) - (mcron-error 13 - "Cannot read files in your ~/.config/cron (or ~/.cron) " - "directory.")))) + (when (eq? 2 errors) + (mcron-error 13 + "Cannot read files in your ~/.config/cron (or ~/.cron) " + "directory.")))) @@ -377,17 +376,16 @@ reading all the information in the users' crontabs and in /etc/crontab.\n (catch-mcron-error (read-vixie-file "/etc/crontab" parse-system-vixie-line)) (use-user-job-list) - (if (not (option-ref options 'noetc #f)) - (begin - (display -"WARNING: cron will check for updates to /etc/crontab EVERY MINUTE. If you do\n + (unless (option-ref options 'noetc #f) + (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 "root") - (job '(- (next-minute-from (next-minute)) 6) - check-system-crontab - "/etc/crontab update checker."))))) + (set-configuration-user "root") + (job '(- (next-minute-from (next-minute)) 6) + check-system-crontab + "/etc/crontab update checker.")))) @@ -410,14 +408,13 @@ option.\n") ;; been explicitly used, or we are running as cron or crond), detach from the ;; terminal now. If we are running as cron, we can now write the PID file. -(if (option-ref options 'daemon (eq? command-type 'cron)) - (begin - (if (not (eqv? (primitive-fork) 0)) - (quit)) - (setsid) - (if (eq? command-type 'cron) - (with-output-to-file config-pid-file - (lambda () (display (getpid)) (newline)))))) +(when (option-ref options 'daemon (eq? command-type 'cron)) + (unless (eqv? (primitive-fork) 0) + (quit)) + (setsid) + (when (eq? command-type 'cron) + (with-output-to-file config-pid-file + (lambda () (display (getpid)) (newline))))) @@ -428,19 +425,19 @@ option.\n") (define fd-list '()) -(if (eq? command-type 'cron) - (catch #t - (lambda () - (let ((socket (socket AF_UNIX SOCK_STREAM 0))) - (bind socket AF_UNIX config-socket-file) - (listen socket 5) - (set! fd-list (list socket)))) - (lambda (key . args) - (delete-file config-pid-file) - (mcron-error 1 - "Cannot bind to UNIX socket " - config-socket-file)))) - +(when (eq? command-type 'cron) + (catch #t + (lambda () + (let ((socket (socket AF_UNIX SOCK_STREAM 0))) + (bind socket AF_UNIX config-socket-file) + (listen socket 5) + (set! fd-list (list socket)))) + (lambda (key . args) + (delete-file config-pid-file) + (mcron-error 1 + "Cannot bind to UNIX socket " + config-socket-file)))) + @@ -489,5 +486,5 @@ option.\n") (catch-mcron-error (while #t (run-job-loop fd-list) - (if (not (null? fd-list)) - (process-update-request)))) + (unless (null? fd-list) + (process-update-request)))) From c8a123839617aae28d87ee02066da73a451ef450 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 12 Aug 2015 18:21:36 +0200 Subject: [PATCH 053/239] main: Turn 'command-name' into a thunk. * scm/mcron/main.scm (command-name): Turn into a thunk. All callers changed. --- scm/mcron/main.scm | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index 39dbe38..227bb8f 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -36,23 +36,21 @@ (mcron core) (mcron job-specifier) (mcron vixie-specification) - (srfi srfi-2)) + (srfi srfi-2) + (srfi srfi-26)) ;; Turn debugging on if indicated. (when config-debug (debug-enable 'debug) (debug-enable 'backtrace)) +(define* (command-name #:optional (command (car (command-line)))) + "Extract the actual command name from COMMAND. This returns the last part +of COMMAND without any non-alphabetic characters. For example \"in.cron\" and +\"./mcron\" will return respectively \"cron\" and \"mcron\". - -;; To determine the name of the program, scan the first item of the command line -;; backwards for the first non-alphabetic character. This allows names like -;; in.cron to be accepted as an invocation of the cron command. - -(define command-name (match:substring (regexp-exec (make-regexp "[[:alpha:]]*$") - (car (command-line))))) - - +When COMMAND is not specified this uses the first element of (command-line)." + (match:substring (regexp-exec (make-regexp "[[:alpha:]]*$") command))) ;; Code contributed by Sergey Poznyakoff. Print an error message (made up from ;; the parts of rest), and if the error is fatal (present and non-zero) then @@ -61,7 +59,7 @@ (define (mcron-error exit-code . rest) (with-output-to-port (current-error-port) (lambda () - (for-each display (append (list command-name ": ") rest)) + (for-each display (append (list (command-name) ": ") rest)) (newline))) (when (and exit-code (not (eq? exit-code 0))) (primitive-exit exit-code))) @@ -83,14 +81,13 @@ ;; We will be doing a lot of testing of the command name, so it makes sense to ;; perform the string comparisons once and for all here. -(define command-type (cond ((string=? command-name "mcron") 'mcron) - ((or (string=? command-name "cron") - (string=? command-name "crond")) 'cron) - ((string=? command-name "crontab") 'crontab) - (else - (mcron-error 12 "The command name is invalid.")))) - - +(define command-type + (let* ((command (command-name)) + (command=? (cut string=? command <>))) + (cond ((command=? "mcron") 'mcron) + ((or (command=? "cron") (command=? "crond")) 'cron) + ((command=? "crontab") 'crontab) + (else (mcron-error 12 "The command name is invalid."))))) ;; There are a different set of options for the crontab personality compared to ;; all the others, with the --help and --version options common to all the @@ -124,7 +121,7 @@ (lambda (key func fmt args . rest) (mcron-error 1 (apply format (append (list #f fmt) args)))))) -(define* (show-version #:optional (command command-name)) +(define* (show-version #:optional (command (command-name))) "Display version information for COMMAND and quit." (let* ((name config-package-name) (short-name (cadr (string-split name #\space))) @@ -149,7 +146,7 @@ General help using GNU software: \n" config-package-name config-package-url)) -(define* (show-help #:optional (command command-name)) +(define* (show-help #:optional (command (command-name))) "Display informations of usage for COMMAND and quit." (simple-format #t "Usage: ~a" command) (display From 2947d841016cc225f9ca92f8d126a2fd3deaaa3e Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 15 Aug 2015 00:05:22 +0200 Subject: [PATCH 054/239] main: Make 'catch-mcron-error' macro hygienic. * scm/mcron/main.scm (catch-mcron-error): Use 'define-syntax-rule' instead of 'defmacro'. --- scm/mcron/main.scm | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index 227bb8f..99531a8 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -64,19 +64,13 @@ When COMMAND is not specified this uses the first element of (command-line)." (when (and exit-code (not (eq? exit-code 0))) (primitive-exit exit-code))) - - -;; Code contributed by Sergey Poznyakoff. Execute body. If an 'mcron-error -;; exception occurs, print its diagnostics and exit with its error code. - -(defmacro catch-mcron-error (. body) - `(catch 'mcron-error - (lambda () - ,@body) - (lambda (key exit-code . msg) - (apply mcron-error exit-code msg)))) - - +(define-syntax-rule (catch-mcron-error exp ...) + "Evaluate EXP .... if an 'mcron-error exception occurs, print its diagnostics +and exit with its error code." + (catch 'mcron-error + (lambda () exp ...) + (lambda (key exit-code . msg) + (apply mcron-error exit-code msg)))) ;; We will be doing a lot of testing of the command name, so it makes sense to ;; perform the string comparisons once and for all here. From 5e8f47fe440699ba236d8f592ddd213b75cf10e7 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 15 Aug 2015 02:32:59 +0200 Subject: [PATCH 055/239] main: Add docstrings. * scm/mcron/main.scm (delete-run-file, mcron-error) (process-files-in-system-directory, process-files-in-user-directory) (process-update-request, process-user-file, regular-file?) (stdin->string, valid-user): Turn comments into docstrings. (command-type, options): Move comments inside the definitions. --- scm/mcron/main.scm | 93 ++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 61 deletions(-) diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index 99531a8..944ea3e 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -52,11 +52,10 @@ of COMMAND without any non-alphabetic characters. For example \"in.cron\" and When COMMAND is not specified this uses the first element of (command-line)." (match:substring (regexp-exec (make-regexp "[[:alpha:]]*$") command))) -;; Code contributed by Sergey Poznyakoff. Print an error message (made up from -;; the parts of rest), and if the error is fatal (present and non-zero) then -;; exit to the system with this code. - (define (mcron-error exit-code . rest) + "Print an error message (made up from the parts of REST), and if the +EXIT-CODE error is fatal (present and non-zero) then exit to the system with +EXIT-CODE." (with-output-to-port (current-error-port) (lambda () (for-each display (append (list (command-name) ": ") rest)) @@ -72,10 +71,9 @@ and exit with its error code." (lambda (key exit-code . msg) (apply mcron-error exit-code msg)))) -;; We will be doing a lot of testing of the command name, so it makes sense to -;; perform the string comparisons once and for all here. - (define command-type + ;; We will be doing a lot of testing of the command name, so it makes sense + ;; to perform the string comparisons once and for all here. (let* ((command (command-name)) (command=? (cut string=? command <>))) (cond ((command=? "mcron") 'mcron) @@ -83,11 +81,10 @@ and exit with its error code." ((command=? "crontab") 'crontab) (else (mcron-error 12 "The command name is invalid."))))) -;; There are a different set of options for the crontab personality compared to -;; all the others, with the --help and --version options common to all the -;; personalities. - (define options + ;; There are a different set of options for the crontab personality compared + ;; to all the others, with the --help and --version options common to all + ;; the personalities. (catch 'misc-error (lambda () @@ -183,12 +180,11 @@ reading all the information in the users' crontabs and in /etc/crontab.\n (when (option-ref options 'help #f) (show-help)) -;; This is called from the C front-end whenever a terminal signal is -;; received. We remove the /var/run/cron.pid file so that crontab and other -;; invocations of cron don't get the wrong idea that a daemon is currently -;; running. - (define (delete-run-file) + "Remove the /var/run/cron.pid file so that crontab and other invocations of +cron don't get the wrong idea that a daemon is currently running. This +procedure is called from the C front-end whenever a terminal signal is +received." (catch #t (lambda () (delete-file config-pid-file) (delete-file config-socket-file)) noop) @@ -224,10 +220,8 @@ reading all the information in the users' crontabs and in /etc/crontab.\n (setenv "MAILTO" #f) (c-set-cron-signals)) - -;; Procedure to slurp the standard input into a string. - (define (stdin->string) + "Return standard input as a string." (with-output-to-string (lambda () (do ((in (read-char) (read-char))) ((eof-object? in)) (display in))))) @@ -243,12 +237,8 @@ reading all the information in the users' crontabs and in /etc/crontab.\n (load "crontab.scm") (quit)) - - -;; Code contributed by Sergey Poznyakoff. Determine if the given file is a -;; regular file or not. - (define (regular-file? file) + "Return true if FILE is a regular file." (catch 'system-error (lambda () (eq? (stat:type (stat file)) 'regular)) @@ -256,16 +246,14 @@ reading all the information in the users' crontabs and in /etc/crontab.\n (mcron-error 0 (apply format (append (list #f fmt) args))) #f))) - - -;; Procedure which processes any configuration file according to the -;; extension. If a file is not recognized, it is silently ignored (this deals -;; properly with most editors' backup files, for instance). - (define guile-file-regexp (make-regexp "\\.gui(le)?$")) (define vixie-file-regexp (make-regexp "\\.vix(ie)?$")) (define (process-user-file file-path . assume-guile) + "Process FILE-PATH according its extension. When ASSUME-GUILE is non nil, +usage of guile syntax is forced for FILE-PATH. If a file is not recognized, +it is silently ignored (this deals properly with most editors' backup files, +for instance)." (cond ((string=? file-path "-") (if (string=? (option-ref options 'stdin "guile") "vixie") (read-vixie-port (current-input-port)) @@ -276,13 +264,9 @@ reading all the information in the users' crontabs and in /etc/crontab.\n ((regexp-exec vixie-file-regexp file-path) (read-vixie-file file-path)))) - - -;; Procedure to run through all the files in a user's ~/.cron and/or -;; $XDG_CONFIG_HOME/cron or ~/.config/cron directories (only happens under the -;; mcron personality). - (define (process-files-in-user-directory) + "Process files in $XDG_CONFIG_HOME/cron and/or ~/.cron directories (if +$XDG_CONFIG_HOME is not defined uses ~/.config/cron instead)." (let ((errors 0) (home-directory (passwd:dir (getpw (getuid))))) (map (lambda (config-directory) @@ -305,13 +289,10 @@ reading all the information in the users' crontabs and in /etc/crontab.\n "Cannot read files in your ~/.config/cron (or ~/.cron) " "directory.")))) - - -;; 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. - (define (valid-user user-name) + "Check that 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, Return the +full passwd entry for that user." (setpwent) (do ((entry (getpw) (getpw))) ((or (not entry) @@ -319,17 +300,11 @@ reading all the information in the users' crontabs and in /etc/crontab.\n (endpwent) entry))) - - -;; Procedure to process all the files in the crontab directory, making sure that -;; each file is for a legitimate user and setting the configuration-user to that -;; user. In this way, when the job procedure is run on behalf of the -;; configuration files, the jobs are registered with the system with the -;; appropriate user. Note that only the root user should be able to perform this -;; operation, but we leave it to the permissions on the /var/cron/tabs directory -;; to enforce this. - (define (process-files-in-system-directory) + "Process all the files in the crontab directory. When the job procedure is +run on behalf of the configuration files, the jobs are registered on the +system with the appropriate user. Only root should be able to perform this +operation. The permissions on the /var/cron/tabs directory enforce this." (catch #t (lambda () (let ((directory (opendir config-spool-dir))) @@ -429,16 +404,12 @@ option.\n") "Cannot bind to UNIX socket " config-socket-file)))) - - - -;; This function is called whenever a message comes in on the above socket. We -;; read a user name from the socket, dealing with the "/etc/crontab" special -;; case, remove all the user's jobs from the job list, and then re-read the -;; user's updated file. In the special case we drop all the system jobs and -;; re-read the /etc/crontab file. - (define (process-update-request) + "Read a user name from the socket, dealing with the /etc/crontab special +case, remove all the user's jobs from the job list, and then re-read the +user's updated file. In the special case drop all the system jobs and re-read +the /etc/crontab file. This function should be called whenever a message +comes in on the above socket." (let* ((socket (car (accept (car fd-list)))) (user-name (read-line socket))) (close socket) From 98d68831ba742e8b8769de3bddf7a695a09ecbbf Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 15 Aug 2015 12:55:47 +0200 Subject: [PATCH 056/239] main: Add 'cron-file-descriptors' procedure. * scm/mcron/main.scm (fd-list): Delete variable. (cron-file-descriptors): New procedure. Return a list instead of mutating 'fd-list'. (process-update-request): Add 'fdes-list' parameter. Adapt caller by using 'cron-file-descriptors' as an effective parameter. --- scm/mcron/main.scm | 57 ++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index 944ea3e..946ab7c 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -382,37 +382,33 @@ option.\n") (with-output-to-file config-pid-file (lambda () (display (getpid)) (newline))))) +(define (cron-file-descriptors) + "Establish a socket to listen for updates from a crontab program, and return +a list containing the file descriptors correponding to the files read by +crontab. This requires that command-type is 'cron." + (if (eq? command-type 'cron) + (catch #t + (lambda () + (let ((sock (socket AF_UNIX SOCK_STREAM 0))) + (bind sock AF_UNIX config-socket-file) + (listen sock 5) + (list sock))) + (lambda (key . args) + (delete-file config-pid-file) + (mcron-error 1 + "Cannot bind to UNIX socket " + config-socket-file))) + '())) - -;; If we are running as cron or crond, we establish a socket to listen for -;; updates from a crontab program. This is put into fd-list so that we can -;; inform the main wait-run-wait execution loop to listen for incoming messages -;; on this socket. - -(define fd-list '()) - -(when (eq? command-type 'cron) - (catch #t - (lambda () - (let ((socket (socket AF_UNIX SOCK_STREAM 0))) - (bind socket AF_UNIX config-socket-file) - (listen socket 5) - (set! fd-list (list socket)))) - (lambda (key . args) - (delete-file config-pid-file) - (mcron-error 1 - "Cannot bind to UNIX socket " - config-socket-file)))) - -(define (process-update-request) +(define (process-update-request fdes-list) "Read a user name from the socket, dealing with the /etc/crontab special case, remove all the user's jobs from the job list, and then re-read the user's updated file. In the special case drop all the system jobs and re-read the /etc/crontab file. This function should be called whenever a message comes in on the above socket." - (let* ((socket (car (accept (car fd-list)))) - (user-name (read-line socket))) - (close socket) + (let* ((sock (car (accept (car fdes-list)))) + (user-name (read-line sock))) + (close sock) (set-configuration-time (current-time)) (catch-mcron-error (if (string=? user-name "/etc/crontab") @@ -443,10 +439,11 @@ comes in on the above socket." ;; core, and when it drops out (can only be because a message has come in on the ;; socket) we process the socket request before restarting the loop again. ;; Sergey Poznyakoff: we can also drop out of run-job-loop because of a SIGCHLD, -;; so must test fd-list. +;; so must test FDES-LIST. (catch-mcron-error - (while #t - (run-job-loop fd-list) - (unless (null? fd-list) - (process-update-request)))) + (let ((fdes-list (cron-file-descriptors))) + (while #t + (run-job-loop fdes-list) + (unless (null? fdes-list) + (process-update-request fdes-list))))) From 237c234f39e59966cacdab4413cc3e200ac2f491 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 15 Aug 2015 23:50:44 +0200 Subject: [PATCH 057/239] main: Add 'main' procedure. * scm/mcron/main.scm (main): New Thunk. Move remaining top-level code to it. --- scm/mcron/main.scm | 238 ++++++++++++++++++++------------------------- 1 file changed, 108 insertions(+), 130 deletions(-) diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index 946ab7c..a964795 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -39,11 +39,6 @@ (srfi srfi-2) (srfi srfi-26)) -;; Turn debugging on if indicated. -(when config-debug - (debug-enable 'debug) - (debug-enable 'backtrace)) - (define* (command-name #:optional (command (car (command-line)))) "Extract the actual command name from COMMAND. This returns the last part of COMMAND without any non-alphabetic characters. For example \"in.cron\" and @@ -125,9 +120,6 @@ There is NO WARRANTY, to the extent permitted by law.\n" command name version short-name) (quit))) -(when (option-ref options 'version #f) - (show-version)) - (define (show-package-information) "Display where to get help and send bug reports." (simple-format #t "\nReport bugs to: ~a.\n @@ -177,9 +169,6 @@ reading all the information in the users' crontabs and in /etc/crontab.\n (show-package-information) (quit)) -(when (option-ref options 'help #f) - (show-help)) - (define (delete-run-file) "Remove the /var/run/cron.pid file so that crontab and other invocations of cron don't get the wrong idea that a daemon is currently running. This @@ -190,53 +179,12 @@ received." noop) (quit)) - - -;; 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. -;; -;; Otherwise, clear the MAILTO environment variable so that output from cron -;; jobs is sent to the various users (this may still be overridden in the -;; configuration files), and call the function in the C wrapper to set up -;; terminal signal responses to vector to the procedure above. The PID file will -;; be filled in properly later when we have forked our daemon process (but not -;; done if we are only viewing the schedules). - -(when (eq? command-type 'cron) - (unless (eqv? (getuid) 0) - (mcron-error 16 - "This program must be run by the root user (and should " - "have been installed as such).")) - (when (access? config-pid-file F_OK) - (mcron-error 1 - "A cron daemon is already running.\n" - " (If you are sure this is not true, remove the file\n" - " " - config-pid-file - ".)")) - (unless (option-ref options 'schedule #f) - (with-output-to-file config-pid-file noop)) - (setenv "MAILTO" #f) - (c-set-cron-signals)) - (define (stdin->string) "Return standard input as a string." (with-output-to-string (lambda () (do ((in (read-char) (read-char))) ((eof-object? in)) (display in))))) - - -;; Now we have the procedures in place for dealing with the contents of -;; configuration files, the crontab personality is able to validate such -;; files. If the user requested the crontab personality, we load and run the -;; code here and then get out. - -(when (eq? command-type 'crontab) - (load "crontab.scm") - (quit)) - (define (regular-file? file) "Return true if FILE is a regular file." (catch 'system-error @@ -321,67 +269,6 @@ operation. The permissions on the /var/cron/tabs directory enforce this." 4 "You do not have permission to access the system crontabs.")))) - - -;; 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 -;; passed on the command line, or else all the ones in the user's .config/cron -;; (or .cron) directory. If we are running under the cron personality, we read -;; the /var/cron/tabs directory and also the /etc/crontab file. - -(case command-type - ((mcron) (if (null? (option-ref options '() '())) - (process-files-in-user-directory) - (for-each (lambda (file-path) - (process-user-file file-path #t)) - (option-ref options '() '())))) - - ((cron) (process-files-in-system-directory) - (use-system-job-list) - (catch-mcron-error - (read-vixie-file "/etc/crontab" parse-system-vixie-line)) - (use-user-job-list) - (unless (option-ref options 'noetc #f) - (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 "root") - (job '(- (next-minute-from (next-minute)) 6) - check-system-crontab - "/etc/crontab update checker.")))) - - - -;; If the user has requested a schedule of jobs that will run, we provide the -;; information here and then get out. -;; -;; Start by determining the number of time points in the future that output is -;; required for. This may be provided on the command line as a parameter to the -;; --schedule option, or else we assume a default of 8. Finally, ensure that the -;; count is some positive integer. - -(and-let* ((count (option-ref options 'schedule #f))) - (set! count (string->number count)) - (display (get-schedule (if (<= count 0) 1 count))) - (quit)) - - - -;; If we are supposed to run as a daemon process (either a --daemon option has -;; been explicitly used, or we are running as cron or crond), detach from the -;; terminal now. If we are running as cron, we can now write the PID file. - -(when (option-ref options 'daemon (eq? command-type 'cron)) - (unless (eqv? (primitive-fork) 0) - (quit)) - (setsid) - (when (eq? command-type 'cron) - (with-output-to-file config-pid-file - (lambda () (display (getpid)) (newline))))) - (define (cron-file-descriptors) "Establish a socket to listen for updates from a crontab program, and return a list containing the file descriptors correponding to the files read by @@ -422,28 +309,119 @@ comes in on the above socket." (set-configuration-user user) (read-vixie-file (string-append config-spool-dir "/" user-name))))))) + +;;; +;;; Entry point. +;;; +(define (main . args) + ;; Turn debugging on if indicated. + (when config-debug + (debug-enable 'debug) + (debug-enable 'backtrace)) + (when (option-ref options 'version #f) + (show-version)) + (when (option-ref options 'help #f) + (show-help)) -;; Added by Sergey Poznyakoff. This no-op will collect zombie child processes -;; as soon as they die. This is a big improvement as previously they stayed -;; around the system until the next time mcron wakes to fire a new job off. + ;; 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. + ;; + ;; Otherwise, clear the MAILTO environment variable so that output from cron + ;; jobs is sent to the various users (this may still be overridden in the + ;; configuration files), and call the function in the C wrapper to set up + ;; terminal signal responses to vector to the procedure above. The PID file + ;; will be filled in properly later when we have forked our daemon process + ;; (but not done if we are only viewing the schedules). + (when (eq? command-type 'cron) + (unless (eqv? (getuid) 0) + (mcron-error 16 + "This program must be run by the root user (and should " + "have been installed as such).")) + (when (access? config-pid-file F_OK) + (mcron-error 1 + "A cron daemon is already running.\n" + " (If you are sure this is not true, remove the file\n" + " " + config-pid-file + ".)")) + (unless (option-ref options 'schedule #f) + (with-output-to-file config-pid-file noop)) + (setenv "MAILTO" #f) + (c-set-cron-signals)) -;; Unfortunately it seems to interact badly with the select system call, -;; wreaking havoc... + ;; Now we have the procedures in place for dealing with the contents of + ;; configuration files, the crontab personality is able to validate such + ;; files. If the user requested the crontab personality, we load and run the + ;; code here and then get out. + (when (eq? command-type 'crontab) + (load "crontab.scm") + (quit)) -;; (sigaction SIGCHLD (lambda (sig) noop) SA_RESTART) + ;; 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 passed on the command line, or else all the ones in the user's + ;; .config/cron (or .cron) directory. If we are running under the cron + ;; personality, we read the /var/cron/tabs directory and also the + ;; /etc/crontab file. + (case command-type + ((mcron) + (if (null? (option-ref options '() '())) + (process-files-in-user-directory) + (for-each (lambda (file-path) (process-user-file file-path #t)) + (option-ref options '() '())))) + ((cron) + (process-files-in-system-directory) + (use-system-job-list) + (catch-mcron-error (read-vixie-file "/etc/crontab" + parse-system-vixie-line)) + (use-user-job-list) + (unless (option-ref options 'noetc #f) + (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 "root") + (job '(- (next-minute-from (next-minute)) 6) + check-system-crontab + "/etc/crontab update checker.")))) + ;; If the user has requested a schedule of jobs that will run, we provide + ;; the information here and then get out. Start by determining the number + ;; of time points in the future that output is required for. This may be + ;; provided on the command line as a parameter to the --schedule option, or + ;; else we assume a default of 8. Finally, ensure that the count is some + ;; positive integer. + (and-let* ((count (option-ref options 'schedule #f))) + (set! count (string->number count)) + (display (get-schedule (if (<= count 0) 1 count))) + (quit)) + ;; If we are supposed to run as a daemon process (either a --daemon option + ;; has been explicitly used, or we are running as cron or crond), detach + ;; from the terminal now. If we are running as cron, we can now write the + ;; PID file. + (when (option-ref options 'daemon (eq? command-type 'cron)) + (unless (eqv? (primitive-fork) 0) + (quit)) + (setsid) + (when (eq? command-type 'cron) + (with-output-to-file config-pid-file + (lambda () (display (getpid)) (newline))))) -;; Now the main loop. Forever execute the run-job-loop procedure in the mcron -;; core, and when it drops out (can only be because a message has come in on the -;; socket) we process the socket request before restarting the loop again. -;; Sergey Poznyakoff: we can also drop out of run-job-loop because of a SIGCHLD, -;; so must test FDES-LIST. + ;; Now the main loop. Forever execute the run-job-loop procedure in the + ;; mcron core, and when it drops out (can only be because a message has come + ;; in on the socket) we process the socket request before restarting the + ;; loop again. Sergey Poznyakoff: we can also drop out of run-job-loop + ;; because of a SIGCHLD, so must test FDES-LIST. + (catch-mcron-error + (let ((fdes-list (cron-file-descriptors))) + (while #t + (run-job-loop fdes-list) + (unless (null? fdes-list) + (process-update-request fdes-list)))))) -(catch-mcron-error - (let ((fdes-list (cron-file-descriptors))) - (while #t - (run-job-loop fdes-list) - (unless (null? fdes-list) - (process-update-request fdes-list))))) +(main) From 3c903bfc808b6fed0c3fff6e78689cfe280d25b3 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 16 Aug 2015 10:33:37 +0200 Subject: [PATCH 058/239] main: Add (mcron main) module. Remove 'ed' hack to eval content of scm/mcron/main.scm in the C wrapper. Use proper libguile functions instead. * scm/mcron/main.scm (mcron main): New module. (show-version, show-package-information, show-help, main): Remove extra newline characters in strings. * mcron.c.template: Rename to ... * mcron.c: ... this. (inner_main): Set current module to (mcron main). * makefile.ed: Delete file. * configure.ac: Remove check for 'ed'. * makefile.am: Adjust accordingly. * .gitignore: Likewise. --- .gitignore | 1 - configure.ac | 4 -- makefile.am | 11 +---- makefile.ed | 34 ------------- mcron.c | 102 ++++++++++++++++++++++++++++++++++++++ mcron.c.template | 120 --------------------------------------------- scm/mcron/main.scm | 106 ++++++++++++++++++--------------------- 7 files changed, 152 insertions(+), 226 deletions(-) delete mode 100644 makefile.ed create mode 100644 mcron.c delete mode 100644 mcron.c.template diff --git a/.gitignore b/.gitignore index 6aaa315..4505cc5 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,6 @@ install-sh makefile makefile.in /mcron -mcron.c /mdate-sh *.o missing diff --git a/configure.ac b/configure.ac index 3826bad..ed6971f 100644 --- a/configure.ac +++ b/configure.ac @@ -64,10 +64,6 @@ AC_CHECK_PROGS(HEAD, head) if test "x$ac_cv_prog_HEAD" = "x"; then AC_MSG_ERROR(head not found) fi -AC_CHECK_PROGS(ED, ed) -if test "x$ac_cv_prog_ED" = "x"; then - AC_MSG_ERROR(ed not found) -fi AC_CHECK_PROGS(WHICH, which) if test "x$ac_cv_prog_WHICH" = "x"; then AC_MSG_ERROR(which not found) diff --git a/makefile.am b/makefile.am index 61fbe56..aa0b24b 100644 --- a/makefile.am +++ b/makefile.am @@ -21,12 +21,9 @@ SUBDIRS = scm/mcron . -ED = @ED@ # !!!! Are these needed? CP = @CP@ -CLEANFILES = mcron.c - -EXTRA_DIST = makefile.ed mcron.c.template BUGS ChangeLog.old +EXTRA_DIST = BUGS ChangeLog.old info_TEXINFOS = doc/mcron.texi doc_mcron_TEXINFOS = doc/fdl.texi @@ -40,12 +37,6 @@ mcron_LDADD = @GUILE_LIBS@ # in turn so that we can do mcron --help during the build process. mcron_CFLAGS = @GUILE_CFLAGS@ -DGUILE_LOAD_PATH=\"$(datadir):./scm:...\" - -mcron.c : scm/mcron/main.scm scm/mcron/crontab.scm makefile.ed mcron.c.template - @echo 'Building mcron.c...' - @$(ED) < makefile.ed > /dev/null 2>&1 - @rm -f mcron.escaped.scm > /dev/null 2>&1 - dist-hook: gen-ChangeLog gen_start_date = 2015-06-26 diff --git a/makefile.ed b/makefile.ed deleted file mode 100644 index 7047ec7..0000000 --- a/makefile.ed +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (C) 2003 Dale Mellor -# -# This file is part of GNU mcron. -# -# GNU mcron is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free -# Software Foundation, either version 3 of the License, or (at your option) -# any later version. -# -# GNU mcron is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along -# with GNU mcron. If not, see . -# -# -# -e scm/mcron/main.scm -/\(load "crontab.scm"\)/d --1r scm/mcron/crontab.scm -%s/\\/\\\\/g -%s/"/\\"/g -%s/ *;;.*$/ /g -g/^ *$/d -%s/^/\"/ -%s/$/\"/ -w mcron.escaped.scm -e mcron.c.template -/GUILE_PROGRAM_GOES_HERE/d --1r mcron.escaped.scm -w mcron.c -q diff --git a/mcron.c b/mcron.c new file mode 100644 index 0000000..6c9efa4 --- /dev/null +++ b/mcron.c @@ -0,0 +1,102 @@ +/* mcron - run jobs at scheduled times + + Copyright (C) 2015, 2016 Mathieu Lirzin + Copyright (C) 2003, 2014 Dale Mellor + + This file is part of GNU Mcron. + + GNU Mcron is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GNU Mcron is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Mcron. If not, see . */ + +/* This C code represents the thinnest possible wrapper around the Guile code + which constitutes all the functionality of the mcron program. There are + two plus one reasons why we need to do this, and one very unfortunate + consequence. + + * Firstly, SUID does not work on an executable script. In the end, it is + the execution of the translator, in our case guile, which determines the + effective user, and it is not wise to make the system guile installation + SUID root! + + * Secondly, executable scripts show up in ugly ways in listings of the + system process table. Guile in particular, with its multi-line + #! ...\ \n -s ...!# + idiosyncracies shows up in process listings in a way that is difficult + to determine what program is actually running. + + * A third reason for the C wrapper which might be mentioned is that a + security-conscious system administrator can choose to only install a + binary, thus removing the possibility of a user studying a guile script + and working out ways of hacking it to his own ends, or worse still + finding a way to modify it to his own ends. + + * Unfortunately, running the guile script from inside a C program means + that the sigaction function does not work. Instead, it is necessary to + perform the signal processing in C. */ + +#include +#include +#include + +/* This is a function designed to be installed as a signal handler, for + signals which are supposed to initiate shutdown of this program. It calls + the scheme procedure (see mcron.scm for details) to do all the work, and + then exits. */ + +void +react_to_terminal_signal (int sig) +{ + scm_c_eval_string ("(delete-run-file)"); + exit (1); +} + +/* This is a function designed to be callable from scheme, and sets up all the + signal handlers required by the cron personality. */ + +SCM +set_cron_signals () +{ + static struct sigaction sa; + + memset (&sa, 0, sizeof (sa)); + sa.sa_handler = react_to_terminal_signal; + sigaction (SIGTERM, &sa, 0); + sigaction (SIGINT, &sa, 0); + sigaction (SIGQUIT, &sa, 0); + sigaction (SIGHUP, &sa, 0); + + return SCM_BOOL_T; +} + +/* The effective main function (i.e. the one that actually does some work). + We register the function above with the guile system, and then execute the + mcron guile program. */ + +void +inner_main (void *closure, int argc, char **argv) +{ + scm_set_current_module (scm_c_resolve_module ("mcron main")); + scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); + scm_c_eval_string ("(main)"); +} + +/* The real main function. Does nothing but start up the guile subsystem. */ + +int +main (int argc, char **argv) +{ + setenv ("GUILE_LOAD_PATH", GUILE_LOAD_PATH, 1); + scm_boot_guile (argc, argv, inner_main, 0); + + return 0; +} diff --git a/mcron.c.template b/mcron.c.template deleted file mode 100644 index e9a755d..0000000 --- a/mcron.c.template +++ /dev/null @@ -1,120 +0,0 @@ -/* -*-c-*- */ -/* - * Copyright (C) 2003, 2014 Dale Mellor - * - * This file is part of GNU mcron. - * - * GNU mcron is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * GNU mcron is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with GNU mcron. If not, see . - */ - - -/* - This C code represents the thinnest possible wrapper around the Guile code - which constitutes all the functionality of the mcron program. There are two - plus one reasons why we need to do this, and one very unfortunate - consequence. - - Firstly, SUID does not work on an executable script. In the end, it is - the execution of the translator, in our case guile, which determines the - effective user, and it is not wise to make the system guile installation - SUID root! - - Secondly, executable scripts show up in ugly ways in listings of the - system process table. Guile in particular, with its multi-line - #! ...\ \n -s ...!# - idiosyncracies shows up in process listings in a way that is difficult - to determine what program is actually running. - - A third reason for the C wrapper which might be mentioned is that a - security-conscious system administrator can choose to only install a - binary, thus removing the possibility of a user studying a guile script - and working out ways of hacking it to his own ends, or worse still - finding a way to modify it to his own ends. - - Unfortunately, running the guile script from inside a C program means - that the sigaction function does not work. Instead, it is necessary to - perform the signal processing in C. - - The guile code itself is substituted for the GU1LE_PROGRAM_GOES_HERE (sic) - token by the makefile, which processes the scheme to make it look like one - big string. -*/ - - - -#include -#include -#include - - - -/* This is a function designed to be installed as a signal handler, for signals - which are supposed to initiate shutdown of this program. It calls the scheme - procedure (see mcron.scm for details) to do all the work, and then exits. */ - -void -react_to_terminal_signal (int sig) -{ - scm_c_eval_string ("(delete-run-file)"); - exit (1); -} - - - -/* This is a function designed to be callable from scheme, and sets up all the - signal handlers required by the cron personality. */ - -SCM -set_cron_signals () -{ - static struct sigaction sa; - memset (&sa, 0, sizeof (sa)); - sa.sa_handler = react_to_terminal_signal; - sigaction (SIGTERM, &sa, 0); - sigaction (SIGINT, &sa, 0); - sigaction (SIGQUIT, &sa, 0); - sigaction (SIGHUP, &sa, 0); - - return SCM_BOOL_T; -} - - - -/* The effective main function (i.e. the one that actually does some work). We - register the function above with the guile system, and then execute the mcron - guile program. */ - -void -inner_main () -{ - scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); - - scm_c_eval_string ( - GUILE_PROGRAM_GOES_HERE - ); -} - - - -/* The real main function. Does nothing but start up the guile subsystem. */ - -int -main (int argc, char **argv) -{ - setenv ("GUILE_LOAD_PATH", GUILE_LOAD_PATH, 1); - - scm_boot_guile (argc, argv, inner_main, 0); - - return 0; -} diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index a964795..1d8c87b 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -16,28 +16,22 @@ ;; You should have received a copy of the GNU General Public License along ;; with GNU mcron. If not, see . +;;; This is the 'main' routine for the whole system; this module is the global +;;; entry point (after the minimal C wrapper); to all intents and purposes the +;;; program is pure Guile and starts here. - -;; This is the 'main' routine for the whole system; the top of this file is the -;; global entry point (after the minimal C wrapper, mcron.c.template); to all -;; intents and purposes the program is pure Guile and starts here. -;; -;; This file is built into mcron.c.template by the makefile, which stringifies -;; the whole lot, and escapes quotation marks and escape characters -;; accordingly. Bear this in mind when considering literal multi-line strings. -;; -;; (l0ad "crontab.scm") (sic) is inlined by the makefile. All other -;; functionality comes through modules in .../share/guile/site/mcron/*.scm. - -(use-modules (ice-9 getopt-long) - (ice-9 rdelim) - (ice-9 regex) - (mcron config) - (mcron core) - (mcron job-specifier) - (mcron vixie-specification) - (srfi srfi-2) - (srfi srfi-26)) +(define-module (mcron main) + #:use-module (ice-9 getopt-long) + #:use-module (ice-9 rdelim) + #:use-module (ice-9 regex) + #:use-module (mcron config) + #:use-module (mcron core) + #:use-module (mcron job-specifier) + #:use-module (mcron vixie-specification) + #:use-module (srfi srfi-2) + #:use-module (srfi srfi-26) + #:export (delete-run-file + main)) (define* (command-name #:optional (command (car (command-line)))) "Extract the actual command name from COMMAND. This returns the last part @@ -112,18 +106,18 @@ and exit with its error code." (let* ((name config-package-name) (short-name (cadr (string-split name #\space))) (version config-package-version)) - (simple-format #t "~a (~a) ~a\n -Copyright (C) 2015 the ~a authors.\n -License GPLv3+: GNU GPL version 3 or later \n -This is free software: you are free to change and redistribute it.\n + (simple-format #t "~a (~a) ~a +Copyright (C) 2015 the ~a authors. +License GPLv3+: GNU GPL version 3 or later +This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.\n" command name version short-name) (quit))) (define (show-package-information) "Display where to get help and send bug reports." - (simple-format #t "\nReport bugs to: ~a.\n -~a home page: <~a>\n + (simple-format #t "\nReport bugs to: ~a. +~a home page: <~a> General help using GNU software: \n" config-package-bugreport config-package-name @@ -135,34 +129,34 @@ General help using GNU software: \n" (display (case command-type ((mcron) - " [OPTIONS] [FILES]\n -Run an mcron process according to the specifications in the FILES (`-' for\n -standard input), or use all the files in ~/.config/cron (or the \n -deprecated ~/.cron) with .guile or .vixie extensions.\n -\n - -v, --version Display version\n - -h, --help Display this help message\n - -sN, --schedule[=]N Display the next N jobs that will be run by mcron\n - -d, --daemon Immediately detach the program from the terminal\n - and run as a daemon process\n - -i, --stdin=(guile|vixie) Format of data passed as standard input or\n + " [OPTIONS] [FILES] +Run an mcron process according to the specifications in the FILES (`-' for +standard input), or use all the files in ~/.config/cron (or the +deprecated ~/.cron) with .guile or .vixie extensions. + + -v, --version Display version + -h, --help Display this help message + -sN, --schedule[=]N Display the next N jobs that will be run by mcron + -d, --daemon Immediately detach the program from the terminal + and run as a daemon process + -i, --stdin=(guile|vixie) Format of data passed as standard input or file arguments (default guile)") ((cron) - " [OPTIONS]\n -Unless an option is specified, run a cron daemon as a detached process, \n -reading all the information in the users' crontabs and in /etc/crontab.\n -\n - -v, --version Display version\n - -h, --help Display this help message\n - -sN, --schedule[=]N Display the next N jobs that will be run by cron\n - -n, --noetc Do not check /etc/crontab for updates (HIGHLY\n + " [OPTIONS] +Unless an option is specified, run a cron daemon as a detached process, +reading all the information in the users' crontabs and in /etc/crontab. + + -v, --version Display version + -h, --help Display this help message + -sN, --schedule[=]N Display the next N jobs that will be run by cron + -n, --noetc Do not check /etc/crontab for updates (HIGHLY RECOMMENDED).") ((crontab) - " [-u user] file\n - crontab [-u user] { -e | -l | -r }\n - (default operation is replace, per 1003.2)\n - -e (edit user's crontab)\n - -l (list user's crontab)\n + " [-u user] file + crontab [-u user] { -e | -l | -r } + (default operation is replace, per 1003.2) + -e (edit user's crontab) + -l (list user's crontab) -r (delete user's crontab") (else "\nrubbish"))) (newline) @@ -379,10 +373,10 @@ comes in on the above socket." parse-system-vixie-line)) (use-user-job-list) (unless (option-ref options 'noetc #f) - (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 + (display "\ +WARNING: cron will check for updates to /etc/crontab EVERY MINUTE. If you do +not use this file, or you are prepared to manually restart cron whenever you +make a change, then it is HIGHLY RECOMMENDED that you use the --noetc option.\n") (set-configuration-user "root") (job '(- (next-minute-from (next-minute)) 6) @@ -423,5 +417,3 @@ option.\n") (run-job-loop fdes-list) (unless (null? fdes-list) (process-update-request fdes-list)))))) - -(main) From 3221c057206ca22c2da599c8c76bbcbb0f36e794 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 16 Aug 2015 15:55:35 +0200 Subject: [PATCH 059/239] build: Compile and install '.go' files. * configure.ac: Set and substitute 'mcronmoduledir'. Check for 'guild' which requires Guile >= 2.0.7. Use 'AC_CANONICAL_HOST'. * scm/mcron/makefile.am (.scm.go): New target. (MODULES, GEN_MODULES, GOBJECTS, CLEANFILES, SUFFIXES) (dist_mcronmodule_DATA, mcronmodule_DATA): New variables. (pkgdata_DATA, EXTRA_DIST): Remove variables. * .gitignore: Adjust accordingly. --- .gitignore | 3 +++ configure.ac | 12 +++++++++-- scm/mcron/main.scm | 2 ++ scm/mcron/makefile.am | 48 ++++++++++++++++++++++++++++++++++++++----- 4 files changed, 58 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 4505cc5..9748b8a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,12 @@ *~ +*.go .deps INSTALL aclocal.m4 autom4te.cache /build-aux/compile +/build-aux/config.guess +/build-aux/config.sub /build-aux/depcomp /build-aux/install-sh /build-aux/mdate-sh diff --git a/configure.ac b/configure.ac index ed6971f..42dfa6e 100644 --- a/configure.ac +++ b/configure.ac @@ -26,6 +26,8 @@ AC_INIT([GNU Mcron], [1.0.8], [bug-mcron@gnu.org]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE +mcronmoduledir="${datarootdir}/guile/site/2.0/mcron" +AC_SUBST([mcronmoduledir]) AC_MSG_CHECKING([whether debugging is requested]) AC_ARG_ENABLE(debug, @@ -45,12 +47,18 @@ AC_SUBST(CONFIG_DEBUG) # We have no interest (hence a no-op), but Debian wants this. AC_ARG_ENABLE(maintainer-mode) - +AC_CANONICAL_HOST AC_PROG_AWK AC_PROG_EGREP AM_PROG_CC_C_O -PKG_CHECK_MODULES(GUILE, guile-2.0) +PKG_CHECK_MODULES([GUILE], [guile-2.0 >= 2.0.7]) +AC_PATH_PROG([GUILE], [guile]) + +# search guild +AC_PATH_PROG([GUILD], [guild]) +AS_IF([test -z "$ac_cv_path_GUILD"], + [AC_MSG_ERROR(['guild' program cannot be found.])]) # Checks for programs. diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index 1d8c87b..6ac2116 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -343,6 +343,8 @@ comes in on the above socket." (unless (option-ref options 'schedule #f) (with-output-to-file config-pid-file noop)) (setenv "MAILTO" #f) + ;; XXX: At compile time, this yields a "possibly unbound variable" + ;; warning, but this is OK since it is bound in the C wrapper. (c-set-cron-signals)) ;; Now we have the procedures in place for dealing with the contents of diff --git a/scm/mcron/makefile.am b/scm/mcron/makefile.am index 931b03b..ab6cae2 100644 --- a/scm/mcron/makefile.am +++ b/scm/mcron/makefile.am @@ -1,10 +1,48 @@ -EXTRA_DIST = main.scm mcron-core.scm vixie-specification.scm \ - crontab.scm environment.scm job-specifier.scm redirect.scm \ - vixie-time.scm +MODULES = \ + environment.scm \ + job-specifier.scm \ + main.scm \ + redirect.scm \ + vixie-specification.scm \ + vixie-time.scm -pkgdata_DATA = core.scm environment.scm job-specifier.scm redirect.scm \ - vixie-time.scm vixie-specification.scm config.scm +GEN_MODULES = \ + config.scm \ + core.scm +GOBJECTS = \ + $(GEN_MODULES:%.scm=%.go) \ + $(MODULES:%.scm=%.go) + +mcronmodule_DATA = \ + $(GOBJECTS) \ + $(GEN_MODULES) + +dist_mcronmodule_DATA = \ + $(MODULES) \ + crontab.scm \ + mcron-core.scm + +# Unset 'GUILE_LOAD_COMPILED_PATH' altogether while compiling. Otherwise, if +# $GUILE_LOAD_COMPILED_PATH contains $(mcronmoduledir), we may find .go files +# in there that are newer than the local .scm files (for instance because the +# user ran 'make install' recently). When that happens, we end up loading +# those previously-installed .go files, which may be stale, thereby breaking +# the whole thing. +# +# XXX: Use the C locale for when Guile lacks +# . +.scm.go: + unset GUILE_LOAD_COMPILED_PATH ; \ + LC_ALL=C \ + $(GUILD) compile \ + --load-path="$(top_builddir)/scm" \ + --load-path="$(top_srcdir)/scm" \ + --warn=format --warn=unbound-variable --warn=arity-mismatch \ + --target="$(host)" --output="$@" "$<" + +SUFFIXES = .go +CLEANFILES = $(GOBJECTS) # If you're wondering, the configure script keeps deleting all files with a name # like core.*, so we have to keep re-making it (I lost a good day's work because From 1712722a7b50e2f449ee94fb5d039757f2426f36 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 18 Aug 2015 17:25:21 +0200 Subject: [PATCH 060/239] build: Enable silent rules by default. * configure.ac (AM_SILENT_RULES): Use macro. * makefile.am (doc/mcron.1): Use $(AM_V_HELP2MAN). (AM_V_HELP2MAN, AM_V_HELP2MAN_, AM_V_HELP2MAN_): New variables. * scm/mcron/makefile.am (.scm.go): Use $(AM_V_GUILEC). (AM_V_GUILEC, AM_V_GUILEC_, AM_V_GUILEC_): New variables. --- configure.ac | 1 + makefile.am | 10 ++++++++-- scm/mcron/makefile.am | 6 ++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 42dfa6e..54481dd 100644 --- a/configure.ac +++ b/configure.ac @@ -25,6 +25,7 @@ AC_PREREQ(2.61) AC_INIT([GNU Mcron], [1.0.8], [bug-mcron@gnu.org]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE +AM_SILENT_RULES([yes]) # enables silent rules by default mcronmoduledir="${datarootdir}/guile/site/2.0/mcron" AC_SUBST([mcronmoduledir]) diff --git a/makefile.am b/makefile.am index aa0b24b..1fcf32e 100644 --- a/makefile.am +++ b/makefile.am @@ -79,9 +79,15 @@ uninstall-hook: rm -f $(fpp){cron,crontab}$(EXEEXT); \ fi +# Extend silent rules to help2man. +AM_V_HELP2MAN = $(AM_V_HELP2MAN_$(V)) +AM_V_HELP2MAN_ = $(AM_V_HELP2MAN_$(AM_DEFAULT_VERBOSITY)) +AM_V_HELP2MAN_0 = @echo " HELP2MAN" $@; # Not part of formal package building, but a rule for manual use to get the # elemental man page. Will only work once the mcron program is installed. doc/mcron.1: mcron.c - -$(HELP2MAN) -n 'a program to run tasks at regular (or not) intervals' \ - ./mcron > $@ + -$(AM_V_HELP2MAN)$(MKDIR_P) `dirname "$@"` ; \ + $(HELP2MAN) \ + -n 'a program to run tasks at regular (or not) intervals' \ + ./mcron > $@ diff --git a/scm/mcron/makefile.am b/scm/mcron/makefile.am index ab6cae2..cb7a6bb 100644 --- a/scm/mcron/makefile.am +++ b/scm/mcron/makefile.am @@ -23,6 +23,11 @@ dist_mcronmodule_DATA = \ crontab.scm \ mcron-core.scm +# Extend silent rules to Guile compilation. +AM_V_GUILEC = $(AM_V_GUILEC_$(V)) +AM_V_GUILEC_ = $(AM_V_GUILEC_$(AM_DEFAULT_VERBOSITY)) +AM_V_GUILEC_0 = @echo " GUILEC " $@; + # Unset 'GUILE_LOAD_COMPILED_PATH' altogether while compiling. Otherwise, if # $GUILE_LOAD_COMPILED_PATH contains $(mcronmoduledir), we may find .go files # in there that are newer than the local .scm files (for instance because the @@ -33,6 +38,7 @@ dist_mcronmodule_DATA = \ # XXX: Use the C locale for when Guile lacks # . .scm.go: + $(AM_V_GUILEC)$(MKDIR_P) `dirname "$@"` ; \ unset GUILE_LOAD_COMPILED_PATH ; \ LC_ALL=C \ $(GUILD) compile \ From c925e9ad0d5ee0160331ad69ec21df0f6113f000 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 18 Aug 2015 17:49:34 +0200 Subject: [PATCH 061/239] main: Remove obsolete Guile debug option. * scm/mcron/main.scm (main): Remove obsolete invocation of 'debug-enable'. --- scm/mcron/main.scm | 1 - 1 file changed, 1 deletion(-) diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index 6ac2116..58f1efa 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -311,7 +311,6 @@ comes in on the above socket." (define (main . args) ;; Turn debugging on if indicated. (when config-debug - (debug-enable 'debug) (debug-enable 'backtrace)) (when (option-ref options 'version #f) (show-version)) From b390063628269abc4f7bbc85cf59c8835d5285db Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 30 Aug 2015 11:24:43 +0200 Subject: [PATCH 062/239] redirect: Use module (ice-9 regex). * scm/mcron/redirect.scm: Use module (ice-9 regex) to prevent variables 'match:prefix', 'match:substring', and 'match:prefix' to be unbound. --- scm/mcron/redirect.scm | 1 + 1 file changed, 1 insertion(+) diff --git a/scm/mcron/redirect.scm b/scm/mcron/redirect.scm index 312b768..af763cb 100644 --- a/scm/mcron/redirect.scm +++ b/scm/mcron/redirect.scm @@ -31,6 +31,7 @@ (define-module (mcron redirect) #:export (with-mail-out) + #:use-module (ice-9 regex) #:use-module ((mcron config) :select (config-sendmail)) #:use-module (mcron vixie-time)) From ba6613fe964b5949b3a58b3e2f65da0601f6b613 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 5 Sep 2015 13:14:03 +0200 Subject: [PATCH 063/239] mcron: Add forward declarations. * mcron.c: Reorder function definitions sequentially. --- mcron.c | 53 ++++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/mcron.c b/mcron.c index 6c9efa4..6297337 100644 --- a/mcron.c +++ b/mcron.c @@ -48,16 +48,30 @@ #include #include -/* This is a function designed to be installed as a signal handler, for - signals which are supposed to initiate shutdown of this program. It calls - the scheme procedure (see mcron.scm for details) to do all the work, and - then exits. */ +/* Forward declarations. */ +void inner_main (void *closure, int argc, char **argv); +void react_to_terminal_signal (int sig); +SCM set_cron_signals (void); + +int +main (int argc, char **argv) +{ + setenv ("GUILE_LOAD_PATH", GUILE_LOAD_PATH, 1); + scm_boot_guile (argc, argv, inner_main, 0); + + return 0; +} + +/* The effective main function (i.e. the one that actually does some work). + We register the function above with the guile system, and then execute the + mcron guile program. */ void -react_to_terminal_signal (int sig) +inner_main (void *closure, int argc, char **argv) { - scm_c_eval_string ("(delete-run-file)"); - exit (1); + scm_set_current_module (scm_c_resolve_module ("mcron main")); + scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); + scm_c_eval_string ("(main)"); } /* This is a function designed to be callable from scheme, and sets up all the @@ -78,25 +92,14 @@ set_cron_signals () return SCM_BOOL_T; } -/* The effective main function (i.e. the one that actually does some work). - We register the function above with the guile system, and then execute the - mcron guile program. */ +/* This is a function designed to be installed as a signal handler, for + signals which are supposed to initiate shutdown of this program. It calls + the scheme procedure (see mcron.scm for details) to do all the work, and + then exits. */ void -inner_main (void *closure, int argc, char **argv) +react_to_terminal_signal (int sig) { - scm_set_current_module (scm_c_resolve_module ("mcron main")); - scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); - scm_c_eval_string ("(main)"); -} - -/* The real main function. Does nothing but start up the guile subsystem. */ - -int -main (int argc, char **argv) -{ - setenv ("GUILE_LOAD_PATH", GUILE_LOAD_PATH, 1); - scm_boot_guile (argc, argv, inner_main, 0); - - return 0; + scm_c_eval_string ("(delete-run-file)"); + exit (1); } From 6cd941e06151239b53aa690d13ebdedd78a0cd53 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 5 Sep 2015 13:20:53 +0200 Subject: [PATCH 064/239] mcron: Use symbolic constants. * mcron.c (main, react_to_terminal_signal): Use EXIT_SUCCESS and EXIT_FAILURE macros instead of magic numbers. --- mcron.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mcron.c b/mcron.c index 6297337..7991612 100644 --- a/mcron.c +++ b/mcron.c @@ -46,6 +46,7 @@ #include #include +#include #include /* Forward declarations. */ @@ -59,7 +60,7 @@ main (int argc, char **argv) setenv ("GUILE_LOAD_PATH", GUILE_LOAD_PATH, 1); scm_boot_guile (argc, argv, inner_main, 0); - return 0; + return EXIT_SUCCESS; } /* The effective main function (i.e. the one that actually does some work). @@ -101,5 +102,5 @@ void react_to_terminal_signal (int sig) { scm_c_eval_string ("(delete-run-file)"); - exit (1); + exit (EXIT_FAILURE); } From 8be6babb3f0a62f461090e153c15ebe42e085cca Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 5 Sep 2015 14:46:20 +0200 Subject: [PATCH 065/239] mcron: Rework comments. * mcron.c: Rework comments. --- mcron.c | 47 ++++++++++------------------------------------- 1 file changed, 10 insertions(+), 37 deletions(-) diff --git a/mcron.c b/mcron.c index 7991612..3f72cfd 100644 --- a/mcron.c +++ b/mcron.c @@ -18,31 +18,9 @@ You should have received a copy of the GNU General Public License along with GNU Mcron. If not, see . */ -/* This C code represents the thinnest possible wrapper around the Guile code - which constitutes all the functionality of the mcron program. There are - two plus one reasons why we need to do this, and one very unfortunate - consequence. - - * Firstly, SUID does not work on an executable script. In the end, it is - the execution of the translator, in our case guile, which determines the - effective user, and it is not wise to make the system guile installation - SUID root! - - * Secondly, executable scripts show up in ugly ways in listings of the - system process table. Guile in particular, with its multi-line - #! ...\ \n -s ...!# - idiosyncracies shows up in process listings in a way that is difficult - to determine what program is actually running. - - * A third reason for the C wrapper which might be mentioned is that a - security-conscious system administrator can choose to only install a - binary, thus removing the possibility of a user studying a guile script - and working out ways of hacking it to his own ends, or worse still - finding a way to modify it to his own ends. - - * Unfortunately, running the guile script from inside a C program means - that the sigaction function does not work. Instead, it is necessary to - perform the signal processing in C. */ +/* This C code represents a thin wrapper around the Guile code of Mcron. It + is needed because the crontab personality requires SUID which is not + permitted for executable scripts. */ #include #include @@ -63,21 +41,19 @@ main (int argc, char **argv) return EXIT_SUCCESS; } -/* The effective main function (i.e. the one that actually does some work). - We register the function above with the guile system, and then execute the - mcron guile program. */ - +/* Launch the Mcron Guile main program. */ void inner_main (void *closure, int argc, char **argv) { scm_set_current_module (scm_c_resolve_module ("mcron main")); + /* Register set_cron_signals to be called from Guile. */ scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); scm_c_eval_string ("(main)"); } -/* This is a function designed to be callable from scheme, and sets up all the - signal handlers required by the cron personality. */ - +/* Set up all the signal handlers as required by the cron personality. This + is necessary to perform the signal processing in C because the sigaction + function won't work when called from Guile. */ SCM set_cron_signals () { @@ -93,11 +69,8 @@ set_cron_signals () return SCM_BOOL_T; } -/* This is a function designed to be installed as a signal handler, for - signals which are supposed to initiate shutdown of this program. It calls - the scheme procedure (see mcron.scm for details) to do all the work, and - then exits. */ - +/* Handle signal SIG and exit. All signals that mcron handles will produce + the same behavior so we don't need to use SIG in the implementation. */ void react_to_terminal_signal (int sig) { From 831b14d9805875862d35fccbeace426b5f55d73d Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 5 Sep 2015 14:52:01 +0200 Subject: [PATCH 066/239] mcron: Mark local functions as static. * mcron.c (inner_main, react_to_terminal_signal, set_cron_signals): Declare static. --- mcron.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mcron.c b/mcron.c index 3f72cfd..0c62ec8 100644 --- a/mcron.c +++ b/mcron.c @@ -28,9 +28,9 @@ #include /* Forward declarations. */ -void inner_main (void *closure, int argc, char **argv); -void react_to_terminal_signal (int sig); -SCM set_cron_signals (void); +static void inner_main (void *closure, int argc, char **argv); +static void react_to_terminal_signal (int sig); +static SCM set_cron_signals (void); int main (int argc, char **argv) @@ -42,7 +42,7 @@ main (int argc, char **argv) } /* Launch the Mcron Guile main program. */ -void +static void inner_main (void *closure, int argc, char **argv) { scm_set_current_module (scm_c_resolve_module ("mcron main")); @@ -54,7 +54,7 @@ inner_main (void *closure, int argc, char **argv) /* Set up all the signal handlers as required by the cron personality. This is necessary to perform the signal processing in C because the sigaction function won't work when called from Guile. */ -SCM +static SCM set_cron_signals () { static struct sigaction sa; @@ -71,7 +71,7 @@ set_cron_signals () /* Handle signal SIG and exit. All signals that mcron handles will produce the same behavior so we don't need to use SIG in the implementation. */ -void +static void react_to_terminal_signal (int sig) { scm_c_eval_string ("(delete-run-file)"); From 805c04fb9033f0d052e3be01eeeed007f940e810 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 6 Sep 2015 03:05:33 +0200 Subject: [PATCH 067/239] main: Improve 'process-user-file' definition. * scm/mcron/main.scm (process-user-file): Rename parameters 'file-path' to 'file-name' and 'assume-guile' to 'guile-syntax?'. Capture 'guile-regexp' and 'vixie-regexp' bindings in the procedure scope. (guile-file-regexp, vixie-file-regexp): Delete variables. --- scm/mcron/main.scm | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index 58f1efa..727f013 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -188,23 +188,21 @@ received." (mcron-error 0 (apply format (append (list #f fmt) args))) #f))) -(define guile-file-regexp (make-regexp "\\.gui(le)?$")) -(define vixie-file-regexp (make-regexp "\\.vix(ie)?$")) - -(define (process-user-file file-path . assume-guile) - "Process FILE-PATH according its extension. When ASSUME-GUILE is non nil, -usage of guile syntax is forced for FILE-PATH. If a file is not recognized, -it is silently ignored (this deals properly with most editors' backup files, -for instance)." - (cond ((string=? file-path "-") - (if (string=? (option-ref options 'stdin "guile") "vixie") - (read-vixie-port (current-input-port)) - (eval-string (stdin->string)))) - ((or (not (null? assume-guile)) - (regexp-exec guile-file-regexp file-path)) - (load file-path)) - ((regexp-exec vixie-file-regexp file-path) - (read-vixie-file file-path)))) +(define process-user-file + (let ((guile-regexp (make-regexp "\\.gui(le)?$")) + (vixie-regexp (make-regexp "\\.vix(ie)?$"))) + (lambda* (file-name #:optional guile-syntax?) + "Process FILE-NAME according its extension. When GUILE-SYNTAX? is TRUE, +force guile syntax usage. If FILE-NAME format is not recognized, it is +silently ignored." + (cond ((string=? "-" file-name) + (if (string=? (option-ref options 'stdin "guile") "vixie") + (read-vixie-port (current-input-port)) + (eval-string (stdin->string)))) + ((or guile-syntax? (regexp-exec guile-regexp file-name)) + (load file-name)) + ((regexp-exec vixie-regexp file-name) + (read-vixie-file file-name)))))) (define (process-files-in-user-directory) "Process files in $XDG_CONFIG_HOME/cron and/or ~/.cron directories (if From 960f6e18170b77bd8b4ae999257105cac11264b6 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 6 Sep 2015 18:10:42 +0200 Subject: [PATCH 068/239] main: Remove unused 'regular-file?' procedure. * scm/mcron/main.scm (regular-file?): Delete procedure. --- scm/mcron/main.scm | 9 --------- 1 file changed, 9 deletions(-) diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index 727f013..0e46945 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -179,15 +179,6 @@ received." ((eof-object? in)) (display in))))) -(define (regular-file? file) - "Return true if FILE is a regular file." - (catch 'system-error - (lambda () - (eq? (stat:type (stat file)) 'regular)) - (lambda (key call fmt args . rest) - (mcron-error 0 (apply format (append (list #f fmt) args))) - #f))) - (define process-user-file (let ((guile-regexp (make-regexp "\\.gui(le)?$")) (vixie-regexp (make-regexp "\\.vix(ie)?$"))) From c2a1d931a6533679d0d1a7e1f9416d44078bd236 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 5 Sep 2015 21:01:49 +0200 Subject: [PATCH 069/239] environment: Redefine 'modify-environment'. * scm/mcron/environment.scm (modify-environment): Add docstring. Compute 'passwd:dir' and 'passwd:name' only once. (impose-default-environment): Merge it into 'modify-environment'. --- scm/mcron/environment.scm | 54 +++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/scm/mcron/environment.scm b/scm/mcron/environment.scm index 9f694f1..b563d55 100644 --- a/scm/mcron/environment.scm +++ b/scm/mcron/environment.scm @@ -1,3 +1,4 @@ +;; Copyright (C) 2015, 2016 Mathieu Lirzin ;; Copyright (C) 2003 Dale Mellor ;; ;; This file is part of GNU mcron. @@ -36,37 +37,6 @@ append-environment-mods get-current-environment-mods-copy)) - - - -;; The env-alist is an association list of variable names and values. Variables -;; later in the list will take precedence over variables before. We return a -;; fixed-up version in which some variables are given specific default values -;; (which the user can override), and two variables which the user is not -;; allowed to control are added at the end of the list. - -(define (impose-default-environment env-alist passwd-entry) - (append `(("HOME" . ,(passwd:dir passwd-entry)) - ("CWD" . ,(passwd:dir passwd-entry)) - ("SHELL" . ,(passwd:shell passwd-entry)) - ("TERM" . #f) - ("TERMCAP" . #f)) - env-alist - `(("LOGNAME" . ,(passwd:name passwd-entry)) - ("USER" . ,(passwd:name passwd-entry))))) - - - - -;; Modify the UNIX environment for the current process according to the given -;; association list of variables, with the default variable values imposed. - -(define (modify-environment env-alist passwd-entry) - (for-each (lambda (variable) - (setenv (car variable) (cdr variable))) - (impose-default-environment env-alist passwd-entry))) - - ;; As we parse configuration files, we build up an alist of environment @@ -103,3 +73,25 @@ (set! current-environment-mods (append current-environment-mods (list (cons name value)))) #t) + +(define (modify-environment env passwd-entry) + "Modify the environment (in the UNIX sense) by setting the variables from +ENV and some default ones which are modulated by PASSWD-ENTRY. \"LOGNAME\" +and \"USER\" environment variables can't be overided by ENV. ENV must be an +alist which associate environment variables to their value. PASSWD-ENTRY must +be an object representing user information which corresponds to a valid entry +in /etc/passwd. The return value is not specified." + (for-each (lambda (pair) (setenv (car pair) (cdr pair))) + (let ((home-dir (passwd:dir passwd-entry)) + (user-name (passwd:name passwd-entry))) + (append + ;; Default environment variables which can be overided by ENV. + `(("HOME" . ,home-dir) + ("CWD" . ,home-dir) + ("SHELL" . ,(passwd:shell passwd-entry)) + ("TERM" . #f) + ("TERMCAP" . #f)) + env + ;; Environment variables with imposed values. + `(("LOGNAME" . ,user-name) + ("USER" . ,user-name)))))) From b2718d2cc9a70eda04822b7c8e11aa3e5fabface Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 19 Apr 2016 22:21:53 +0200 Subject: [PATCH 070/239] maint: Define directory-local variables for Emacs. This configures Emacs automatically. * .dir-locals.el: New file. --- .dir-locals.el | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .dir-locals.el diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 0000000..12a5eb5 --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,7 @@ +;; Per-directory local variables for GNU Emacs 23 and later. + +((nil . ((fill-column . 78) + (tab-width . 8))) + (c-mode . ((c-file-style . "gnu") + (indent-tabs-mode . nil))) + (scheme-mode . ((indent-tabs-mode . nil)))) From f2c56d355f883dd60aef020b4e363739aeff856c Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 7 Sep 2015 00:00:31 +0200 Subject: [PATCH 071/239] all: Add a custom indentation rule for 'mcron-error'. * .dir-locals.el: Define a custom indentation rule for 'mcron-error'. * scm/mcron/crontab.scm: Use it. * scm/mcron/job-specifier.scm: Likewise. * scm/mcron/main.scm: Likewise. * scm/mcron/vixie-specification.scm: Likewise. --- .dir-locals.el | 5 ++++- scm/mcron/crontab.scm | 4 ++-- scm/mcron/job-specifier.scm | 14 ++++++-------- scm/mcron/main.scm | 23 ++++++++--------------- scm/mcron/vixie-specification.scm | 12 +++++------- 5 files changed, 25 insertions(+), 33 deletions(-) diff --git a/.dir-locals.el b/.dir-locals.el index 12a5eb5..c94ea0c 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -4,4 +4,7 @@ (tab-width . 8))) (c-mode . ((c-file-style . "gnu") (indent-tabs-mode . nil))) - (scheme-mode . ((indent-tabs-mode . nil)))) + (scheme-mode + . + ((indent-tabs-mode . nil) + (eval . (put 'mcron-error 'scheme-indent-function 1))))) diff --git a/scm/mcron/crontab.scm b/scm/mcron/crontab.scm index 30e5592..6be5c61 100644 --- a/scm/mcron/crontab.scm +++ b/scm/mcron/crontab.scm @@ -221,8 +221,8 @@ ;; The user is being silly. The message here is identical to the one Vixie cron ;; used to put out, for total compatibility. - (else - (mcron-error 15 "usage error: file name must be specified for replace."))) + (else (mcron-error 15 + "usage error: file name must be specified for replace."))) )) ;; End of file-level let-scopes. diff --git a/scm/mcron/job-specifier.scm b/scm/mcron/job-specifier.scm index cce948c..1647ede 100644 --- a/scm/mcron/job-specifier.scm +++ b/scm/mcron/job-specifier.scm @@ -233,10 +233,9 @@ ((list? action) (lambda () (primitive-eval action))) ((string? action) (lambda () (system action))) (else - (throw 'mcron-error - 2 - "job: invalid second argument (action; should be lambda" - " function, string or list)")))) + (throw 'mcron-error 2 + "job: invalid second argument (action; should be lambda " + "function, string or list)")))) (time-proc (cond ((procedure? time-proc) time-proc) @@ -244,10 +243,9 @@ ((list? time-proc) (lambda (current-time) (primitive-eval time-proc))) (else - (throw 'mcron-error - 3 - "job: invalid first argument (next-time-function; should ") - "be function, string or list)"))) + (throw 'mcron-error 3 + "job: invalid first argument (next-time-function; " + "should be function, string or list)")))) (displayable (cond ((not (null? displayable)) (car displayable)) ((procedure? action) "Lambda function") diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index 0e46945..9425cef 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -217,8 +217,7 @@ $XDG_CONFIG_HOME is not defined uses ~/.config/cron instead)." "/cron"))) (when (eq? 2 errors) (mcron-error 13 - "Cannot read files in your ~/.config/cron (or ~/.cron) " - "directory.")))) + "Cannot read files in your ~/.config/cron (or ~/.cron) directory.")))) (define (valid-user user-name) "Check that USER-NAME is in the passwd database (it may happen that a user @@ -248,9 +247,8 @@ operation. The permissions on the /var/cron/tabs directory enforce this." "/" file-name))))))) (lambda (key . args) - (mcron-error - 4 - "You do not have permission to access the system crontabs.")))) + (mcron-error 4 + "You do not have permission to access the system crontabs.")))) (define (cron-file-descriptors) "Establish a socket to listen for updates from a crontab program, and return @@ -265,9 +263,7 @@ crontab. This requires that command-type is 'cron." (list sock))) (lambda (key . args) (delete-file config-pid-file) - (mcron-error 1 - "Cannot bind to UNIX socket " - config-socket-file))) + (mcron-error 1 "Cannot bind to UNIX socket " config-socket-file))) '())) (define (process-update-request fdes-list) @@ -319,15 +315,12 @@ comes in on the above socket." (when (eq? command-type 'cron) (unless (eqv? (getuid) 0) (mcron-error 16 - "This program must be run by the root user (and should " - "have been installed as such).")) + "This program must be run by the root user (and should have been " + "installed as such).")) (when (access? config-pid-file F_OK) (mcron-error 1 - "A cron daemon is already running.\n" - " (If you are sure this is not true, remove the file\n" - " " - config-pid-file - ".)")) + "A cron daemon is already running.\n (If you are sure this is not" + " true, remove the file\n " config-pid-file ".)")) (unless (option-ref options 'schedule #f) (with-output-to-file config-pid-file noop)) (setenv "MAILTO" #f) diff --git a/scm/mcron/vixie-specification.scm b/scm/mcron/vixie-specification.scm index ab002ba..5cd1528 100644 --- a/scm/mcron/vixie-specification.scm +++ b/scm/mcron/vixie-specification.scm @@ -162,13 +162,11 @@ (parse-vixie-environment line) (parse-vixie-line line))) (lambda (key exit-code . msg) - (throw - 'mcron-error - exit-code - (apply string-append - (number->string report-line) - ": " - msg))))))))) + (throw 'mcron-error exit-code + (apply string-append + (number->string report-line) + ": " + msg))))))))) From 4da7aec83b6f8f854568ac150ed129502486bf14 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 7 Sep 2015 00:50:14 +0200 Subject: [PATCH 072/239] main: Add 'for-each-file' procedure. * scm/mcron/main.scm (for-each-file): New procedure. (process-files-in-user-directory, process-files-in-system-directory): Use it. --- scm/mcron/main.scm | 61 +++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index 9425cef..a84f82f 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -179,6 +179,15 @@ received." ((eof-object? in)) (display in))))) +(define (for-each-file proc directory) + "Apply PROC to each file in DIRECTORY. DIRECTORY must be a valid directory name. +PROC must be a procedure that take one file name argument. The return value +is not specified" + (let ((dir (opendir directory))) + (do ((file-name (readdir dir) (readdir dir))) + ((eof-object? file-name) (closedir dir)) + (proc file-name)))) + (define process-user-file (let ((guile-regexp (make-regexp "\\.gui(le)?$")) (vixie-regexp (make-regexp "\\.vix(ie)?$"))) @@ -200,21 +209,19 @@ silently ignored." $XDG_CONFIG_HOME is not defined uses ~/.config/cron instead)." (let ((errors 0) (home-directory (passwd:dir (getpw (getuid))))) - (map (lambda (config-directory) - (catch #t - (lambda () - (let ((directory (opendir config-directory))) - (do ((file-name (readdir directory) (readdir directory))) - ((eof-object? file-name) (closedir directory)) - (process-user-file (string-append config-directory - "/" - file-name))))) - (lambda (key . args) - (set! errors (1+ errors))))) - (list (string-append home-directory "/.cron") - (string-append (or (getenv "XDG_CONFIG_HOME") - (string-append home-directory "/.config")) - "/cron"))) + (map (lambda (dir) + (catch #t + (lambda () + (for-each-file + (lambda (file) + (process-user-file (string-append dir "/" file))) + dir)) + (lambda (key . args) + (set! errors (1+ errors))))) + (list (string-append home-directory "/.cron") + (string-append (or (getenv "XDG_CONFIG_HOME") + (string-append home-directory "/.config")) + "/cron"))) (when (eq? 2 errors) (mcron-error 13 "Cannot read files in your ~/.config/cron (or ~/.cron) directory.")))) @@ -236,19 +243,17 @@ run on behalf of the configuration files, the jobs are registered on the system with the appropriate user. Only root should be able to perform this operation. The permissions on the /var/cron/tabs directory enforce this." (catch #t - (lambda () - (let ((directory (opendir config-spool-dir))) - (do ((file-name (readdir directory) (readdir directory))) - ((eof-object? file-name)) - (and-let* ((user (valid-user file-name))) - (set-configuration-user user) ;; / ?? !!!! - (catch-mcron-error - (read-vixie-file (string-append config-spool-dir - "/" - file-name))))))) - (lambda (key . args) - (mcron-error 4 - "You do not have permission to access the system crontabs.")))) + (lambda () + (for-each-file + (lambda (user) + (and-let* ((user* (valid-user user))) ;crontab without user? + (set-configuration-user user*) + (catch-mcron-error + (read-vixie-file (string-append config-spool-dir "/" user))))) + config-spool-dir)) + (lambda (key . args) + (mcron-error 4 + "You do not have permission to access the system crontabs.")))) (define (cron-file-descriptors) "Establish a socket to listen for updates from a crontab program, and return From fdbaa674a73c04681d574a4eabf5a723dc716d38 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 7 Sep 2015 00:54:45 +0200 Subject: [PATCH 073/239] main: Remove 'valid-user' procedure. * scm/mcron/main.scm (valid-user): Delete procedure. (process-files-in-system-directory): Adjust accordingly by using a local definition. --- scm/mcron/main.scm | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index a84f82f..1f2b068 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -226,28 +226,22 @@ $XDG_CONFIG_HOME is not defined uses ~/.config/cron instead)." (mcron-error 13 "Cannot read files in your ~/.config/cron (or ~/.cron) directory.")))) -(define (valid-user user-name) - "Check that 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, Return the -full passwd entry for that user." - (setpwent) - (do ((entry (getpw) (getpw))) - ((or (not entry) - (string=? (passwd:name entry) user-name)) - (endpwent) - entry))) - (define (process-files-in-system-directory) "Process all the files in the crontab directory. When the job procedure is run on behalf of the configuration files, the jobs are registered on the system with the appropriate user. Only root should be able to perform this operation. The permissions on the /var/cron/tabs directory enforce this." + + (define (user-entry name) + ;; Return the user database entry if NAME is valid, otherwise #f. + (false-if-exception (getpwnam name))) + (catch #t (lambda () (for-each-file (lambda (user) - (and-let* ((user* (valid-user user))) ;crontab without user? - (set-configuration-user user*) + (and-let* ((entry (user-entry user))) ;crontab without user? + (set-configuration-user entry) (catch-mcron-error (read-vixie-file (string-append config-spool-dir "/" user))))) config-spool-dir)) From 589d5ff8d152be5d21c49790dff92ccb27d6c291 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 23 Sep 2015 22:09:23 +0200 Subject: [PATCH 074/239] core: Use SRFI-9 records for the job data structure. * scm/mcron/mcron-core.scm : New record type. This Replaces a vector data structure. All consumers changed. --- scm/mcron/mcron-core.scm | 93 ++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/scm/mcron/mcron-core.scm b/scm/mcron/mcron-core.scm index 518bcac..13781c9 100644 --- a/scm/mcron/mcron-core.scm +++ b/scm/mcron/mcron-core.scm @@ -1,3 +1,4 @@ +;; Copyright (C) 2015, 2016 Mathieu Lirzin ;; Copyright (C) 2003 Dale Mellor ;; ;; This file is part of GNU mcron. @@ -19,6 +20,7 @@ (define-module (mcron core) #:use-module (mcron environment) + #:use-module (srfi srfi-9) #:export (add-job remove-user-jobs get-schedule @@ -38,7 +40,7 @@ ;; The list of all jobs known to the system. Each element of the list is ;; -;; (vector user next-time-function action environment displayable next-time) +;; (make-job user next-time-function action environment displayable next-time) ;; ;; where action must be a procedure, and the environment is an alist of ;; modifications that need making to the UNIX environment before the action is @@ -60,18 +62,17 @@ (define (use-system-job-list) (set! configuration-source 'system)) (define (use-user-job-list) (set! configuration-source 'user)) - - -;; Convenience functions for getting and setting the elements of a job object. - -(define (job:user job) (vector-ref job 0)) -(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:displayable job) (vector-ref job 4)) -(define (job:next-time job) (vector-ref job 5)) - - +;; A cron job. +(define-record-type + (make-job user time-proc action environment displayable next-time) + job? + (user job:user) ;object : passwd entry + (time-proc job:next-time-function) ;proc : with one 'time' parameter + (action job:action) ;thunk : user's code + (environment job:environment) ;alist : environment variables + (displayable job:displayable) ;string : visible in schedule + (next-time job:next-time ;number : time in UNIX format + job:next-time-set!)) ;; Remove jobs from the user-job-list belonging to this user. @@ -97,12 +98,12 @@ (define (add-job time-proc action displayable configuration-time configuration-user) - (let ((entry (vector configuration-user - time-proc - action - (get-current-environment-mods-copy) - displayable - (time-proc configuration-time)))) + (let ((entry (make-job configuration-user + time-proc + action + (get-current-environment-mods-copy) + displayable + (time-proc configuration-time)))) (if (eq? configuration-source 'user) (set! user-job-list (cons entry user-job-list)) (set! system-job-list (cons entry system-job-list))))) @@ -165,18 +166,17 @@ (lambda () (do ((count count (- count 1))) ((eqv? count 0)) - (and-let* ((next-jobs (find-next-jobs)) - (time (car next-jobs)) - (date-string (strftime "%c %z\n" (localtime time)))) - (for-each (lambda (job) - (display date-string) - (display (job:displayable job)) - (newline)(newline) - (vector-set! job - 5 - ((job:next-time-function job) - (job:next-time job)))) - (cdr next-jobs))))))) + (and-let* + ((next-jobs (find-next-jobs)) + (time (car next-jobs)) + (date-string (strftime "%c %z\n" (localtime time)))) + (for-each (lambda (job) + (display date-string) + (display (job:displayable job)) + (newline)(newline) + (job:next-time-set! job ((job:next-time-function job) + (job:next-time job)))) + (cdr next-jobs))))))) @@ -195,22 +195,21 @@ ;; to run. (define (run-jobs jobs-list) - (for-each (lambda (job) - (if (eqv? (primitive-fork) 0) - (begin - (setgid (passwd:gid (job:user job))) - (setuid (passwd:uid (job:user job))) - (chdir (passwd:dir (job:user job))) - (modify-environment (job:environment job) (job:user job)) - ((job:action job)) - (primitive-exit 0)) - (begin - (set! number-children (+ number-children 1)) - (vector-set! job - 5 - ((job:next-time-function job) - (current-time)))))) - jobs-list)) + (for-each + (lambda (job) + (if (eqv? (primitive-fork) 0) + (begin + (setgid (passwd:gid (job:user job))) + (setuid (passwd:uid (job:user job))) + (chdir (passwd:dir (job:user job))) + (modify-environment (job:environment job) (job:user job)) + ((job:action job)) + (primitive-exit 0)) + (begin + (set! number-children (+ number-children 1)) + (job:next-time-set! job ((job:next-time-function job) + (current-time)))))) + jobs-list)) From b59f2f5ea6f99681ca61f9342206c11f3a165b2c Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 17 Oct 2015 19:56:03 +0200 Subject: [PATCH 075/239] build: Use a non-recursive makefile. * configure.ac (AM_INIT_AUTOMAKE): Use 'subdir-objects' option. (AC_CONFIG_FILES): Remove 'scm/mcron/makefile' and 'makefile'. Add 'Makefile'. * makefile.am: Delete file. Move its content into ... * scm/mcron/makefile.am: Likewise. * Makefile.am: ... this. New file. * .gitignore: Update. --- .gitignore | 30 ++++----- Makefile.am | 145 ++++++++++++++++++++++++++++++++++++++++++ configure.ac | 5 +- makefile.am | 93 --------------------------- scm/mcron/makefile.am | 59 ----------------- 5 files changed, 162 insertions(+), 170 deletions(-) create mode 100644 Makefile.am delete mode 100644 makefile.am delete mode 100644 scm/mcron/makefile.am diff --git a/.gitignore b/.gitignore index 9748b8a..3aa3599 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,7 @@ -*~ *.go +*.o +*~ .deps -INSTALL -aclocal.m4 -autom4te.cache /build-aux/compile /build-aux/config.guess /build-aux/config.sub @@ -12,6 +10,19 @@ autom4te.cache /build-aux/mdate-sh /build-aux/missing /build-aux/texinfo.tex +/doc/.dirstamp +/doc/config.texi +/doc/mcron.1 +/doc/mcron.info +/doc/stamp-vti +/doc/version.texi +/mcron +/mdate-sh +INSTALL +Makefile +Makefile.in +aclocal.m4 +autom4te.cache compile config.cache config.log @@ -20,17 +31,6 @@ config.status configure core.scm depcomp -/doc/.dirstamp -/doc/config.texi -/doc/mcron.info -/doc/mcron.1 -/doc/stamp-vti -/doc/version.texi install-sh -makefile -makefile.in -/mcron -/mdate-sh -*.o missing texinfo.tex diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..8c7b4d0 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,145 @@ +## Process this file with automake to produce Makefile.in. + +# Copyright (C) 2003 Dale Mellor +# Copyright (C) 2015, 2016 Mathieu Lirzin +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +bin_PROGRAMS = mcron +mcron_SOURCES = mcron.c +mcron_CFLAGS = @GUILE_CFLAGS@ -DGUILE_LOAD_PATH=\"$(datadir):./scm:...\" +mcron_DEPENDENCIES = $(GOBJECTS) # Build Guile modules before linking. +mcron_LDADD = @GUILE_LIBS@ + +MODULES = \ + scm/mcron/environment.scm \ + scm/mcron/job-specifier.scm \ + scm/mcron/main.scm \ + scm/mcron/redirect.scm \ + scm/mcron/vixie-specification.scm \ + scm/mcron/vixie-time.scm + +GEN_MODULES = \ + scm/mcron/config.scm \ + scm/mcron/core.scm + +CP = @CP@ +# XXX: Prevent the 'configure' script to delete the 'core.*' files. +scm/mcron/core.scm: scm/mcron/mcron-core.scm + $(CP) $< $@ + +GOBJECTS = \ + $(GEN_MODULES:%.scm=%.go) \ + $(MODULES:%.scm=%.go) + +mcronmodule_DATA = \ + $(GOBJECTS) \ + $(GEN_MODULES) + +dist_mcronmodule_DATA = \ + $(MODULES) \ + scm/mcron/crontab.scm \ + scm/mcron/mcron-core.scm + +# Unset 'GUILE_LOAD_COMPILED_PATH' altogether while compiling. Otherwise, if +# $GUILE_LOAD_COMPILED_PATH contains $(mcronmoduledir), we may find .go files +# in there that are newer than the local .scm files (for instance because the +# user ran 'make install' recently). When that happens, we end up loading +# those previously-installed .go files, which may be stale, thereby breaking +# the whole thing. +# +# XXX: Use the C locale for when Guile lacks +# . +.scm.go: + $(AM_V_GUILEC)$(MKDIR_P) `dirname "$@"` ; \ + unset GUILE_LOAD_COMPILED_PATH ; \ + LC_ALL=C \ + $(GUILD) compile \ + --load-path="$(top_builddir)/scm" \ + --load-path="$(top_srcdir)/scm" \ + --warn=format --warn=unbound-variable --warn=arity-mismatch \ + --target="$(host)" --output="$@" "$<" + +SUFFIXES = .go + +dist-hook: gen-ChangeLog + +gen_start_date = 2015-06-26 +.PHONY: gen-ChangeLog +gen-ChangeLog: + $(AM_V_GEN)if test -d $(srcdir)/.git; then \ + log_fix="$(srcdir)/build-aux/git-log-fix"; \ + test -e "$$log_fix" \ + && amend_git_log="--amend=$$log_fix" \ + || amend_git_log=; \ + $(top_srcdir)/build-aux/gitlog-to-changelog \ + $$amend_git_log --since=$(gen_start_date) > $(distdir)/cl-t && \ + { rm -f $(distdir)/ChangeLog && \ + mv $(distdir)/cl-t $(distdir)/ChangeLog; } \ + fi + +#full program prefix +fpp = $(DESTDIR)$(bindir)/@real_program_prefix@ + +install-exec-hook: + @if [ "x@NO_VIXIE_CLOBBER@" != "xyes" -a "`id -u`" -eq "0" ]; then \ + 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); \ + $(INSTALL) -d --mode='u=rwx' $(DESTDIR)/var/cron; \ + $(INSTALL) -d --mode='u=rwx,og=rx' $(DESTDIR)/var/run; \ + $(INSTALL) -d --mode='u=rwx,og=rx' $(DESTDIR)@GUILE_SITE@; \ + $(INSTALL) -d --mode='u=rwx,og=rx' $(DESTDIR)@GUILE_SITE@/mcron; \ + elif [ "x@NO_VIXIE_CLOBBER@" = "xyes" ]; then \ + echo "Not installing Vixie-style programs"; \ + else \ + echo "+++ WARNING: NON-ROOT INSTALL: ONLY mcron WILL BE INSTALLED, NOT ANY OF THE VIXIE REPLACEMENT PROGRAMS"; \ + fi + +uninstall-hook: + if [ "`id -u`" -eq "0" ]; then \ + rm -f $(fpp){cron,crontab}$(EXEEXT); \ + fi + +EXTRA_DIST = BUGS +CLEANFILES = $(GOBJECTS) + +## --------------- ## +## Documentation. ## +## --------------- ## + +info_TEXINFOS = doc/mcron.texi +doc_mcron_TEXINFOS = doc/fdl.texi +dist_man_MANS = doc/mcron.1 + +# Not part of formal package building, but a rule for manual use to get the +# elemental man page. Will only work once the mcron program is installed. +doc/mcron.1: mcron.c + -$(AM_V_HELP2MAN)$(MKDIR_P) `dirname "$@"` ; \ + $(HELP2MAN) \ + -n 'a program to run tasks at regular (or not) intervals' \ + ./mcron > $@ + +## -------------- ## +## Silent rules. ## +## -------------- ## + +AM_V_GUILEC = $(AM_V_GUILEC_$(V)) +AM_V_GUILEC_ = $(AM_V_GUILEC_$(AM_DEFAULT_VERBOSITY)) +AM_V_GUILEC_0 = @echo " GUILEC " $@; + +AM_V_HELP2MAN = $(AM_V_HELP2MAN_$(V)) +AM_V_HELP2MAN_ = $(AM_V_HELP2MAN_$(AM_DEFAULT_VERBOSITY)) +AM_V_HELP2MAN_0 = @echo " HELP2MAN" $@; diff --git a/configure.ac b/configure.ac index 54481dd..9972ad5 100644 --- a/configure.ac +++ b/configure.ac @@ -24,7 +24,7 @@ AC_PREREQ(2.61) AC_INIT([GNU Mcron], [1.0.8], [bug-mcron@gnu.org]) AC_CONFIG_AUX_DIR([build-aux]) -AM_INIT_AUTOMAKE +AM_INIT_AUTOMAKE([subdir-objects]) AM_SILENT_RULES([yes]) # enables silent rules by default mcronmoduledir="${datarootdir}/guile/site/2.0/mcron" @@ -182,7 +182,6 @@ real_program_prefix=`echo $program_prefix | sed s/NONE//` AC_SUBST(real_program_prefix) AC_CONFIG_FILES([doc/config.texi - makefile - scm/mcron/makefile + Makefile scm/mcron/config.scm]) AC_OUTPUT diff --git a/makefile.am b/makefile.am deleted file mode 100644 index 1fcf32e..0000000 --- a/makefile.am +++ /dev/null @@ -1,93 +0,0 @@ -## Makefile for the toplevel directory of mcron. -## Copyright (C) 2003 Dale Mellor -## Copyright (C) 2015 Mathieu Lirzin -## -# This file is part of GNU mcron. -# -# GNU mcron is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free -# Software Foundation, either version 3 of the License, or (at your option) -# any later version. -# -# GNU mcron is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along -# with GNU mcron. If not, see . - -## Process this file with automake to produce Makefile.in - -SUBDIRS = scm/mcron . - -CP = @CP@ - -EXTRA_DIST = BUGS ChangeLog.old - -info_TEXINFOS = doc/mcron.texi -doc_mcron_TEXINFOS = doc/fdl.texi -dist_man_MANS = doc/mcron.1 - -bin_PROGRAMS = mcron -mcron_SOURCES = mcron.c -mcron_LDADD = @GUILE_LIBS@ - -# The second option is so that we can execute the binary in the local directory, -# in turn so that we can do mcron --help during the build process. -mcron_CFLAGS = @GUILE_CFLAGS@ -DGUILE_LOAD_PATH=\"$(datadir):./scm:...\" - -dist-hook: gen-ChangeLog - -gen_start_date = 2015-06-26 -.PHONY: gen-ChangeLog -gen-ChangeLog: - $(AM_V_GEN)if test -d $(srcdir)/.git; then \ - log_fix="$(srcdir)/build-aux/git-log-fix"; \ - test -e "$$log_fix" \ - && amend_git_log="--amend=$$log_fix" \ - || amend_git_log=; \ - $(top_srcdir)/build-aux/gitlog-to-changelog \ - $$amend_git_log --since=$(gen_start_date) > $(distdir)/cl-t && \ - { rm -f $(distdir)/ChangeLog && \ - mv $(distdir)/cl-t $(distdir)/ChangeLog; } \ - fi - -#full program prefix -fpp = $(DESTDIR)$(bindir)/@real_program_prefix@ - - -install-exec-hook: - @if [ "x@NO_VIXIE_CLOBBER@" != "xyes" -a "`id -u`" -eq "0" ]; then \ - 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); \ - $(INSTALL) -d --mode='u=rwx' $(DESTDIR)/var/cron; \ - $(INSTALL) -d --mode='u=rwx,og=rx' $(DESTDIR)/var/run; \ - $(INSTALL) -d --mode='u=rwx,og=rx' $(DESTDIR)@GUILE_SITE@; \ - $(INSTALL) -d --mode='u=rwx,og=rx' $(DESTDIR)@GUILE_SITE@/mcron; \ - elif [ "x@NO_VIXIE_CLOBBER@" = "xyes" ]; then \ - echo "Not installing Vixie-style programs"; \ - else \ - echo "+++ WARNING: NON-ROOT INSTALL: ONLY mcron WILL BE INSTALLED, NOT ANY OF THE VIXIE REPLACEMENT PROGRAMS"; \ - fi - - -uninstall-hook: - if [ "`id -u`" -eq "0" ]; then \ - rm -f $(fpp){cron,crontab}$(EXEEXT); \ - fi - -# Extend silent rules to help2man. -AM_V_HELP2MAN = $(AM_V_HELP2MAN_$(V)) -AM_V_HELP2MAN_ = $(AM_V_HELP2MAN_$(AM_DEFAULT_VERBOSITY)) -AM_V_HELP2MAN_0 = @echo " HELP2MAN" $@; - -# Not part of formal package building, but a rule for manual use to get the -# elemental man page. Will only work once the mcron program is installed. -doc/mcron.1: mcron.c - -$(AM_V_HELP2MAN)$(MKDIR_P) `dirname "$@"` ; \ - $(HELP2MAN) \ - -n 'a program to run tasks at regular (or not) intervals' \ - ./mcron > $@ diff --git a/scm/mcron/makefile.am b/scm/mcron/makefile.am deleted file mode 100644 index cb7a6bb..0000000 --- a/scm/mcron/makefile.am +++ /dev/null @@ -1,59 +0,0 @@ -MODULES = \ - environment.scm \ - job-specifier.scm \ - main.scm \ - redirect.scm \ - vixie-specification.scm \ - vixie-time.scm - -GEN_MODULES = \ - config.scm \ - core.scm - -GOBJECTS = \ - $(GEN_MODULES:%.scm=%.go) \ - $(MODULES:%.scm=%.go) - -mcronmodule_DATA = \ - $(GOBJECTS) \ - $(GEN_MODULES) - -dist_mcronmodule_DATA = \ - $(MODULES) \ - crontab.scm \ - mcron-core.scm - -# Extend silent rules to Guile compilation. -AM_V_GUILEC = $(AM_V_GUILEC_$(V)) -AM_V_GUILEC_ = $(AM_V_GUILEC_$(AM_DEFAULT_VERBOSITY)) -AM_V_GUILEC_0 = @echo " GUILEC " $@; - -# Unset 'GUILE_LOAD_COMPILED_PATH' altogether while compiling. Otherwise, if -# $GUILE_LOAD_COMPILED_PATH contains $(mcronmoduledir), we may find .go files -# in there that are newer than the local .scm files (for instance because the -# user ran 'make install' recently). When that happens, we end up loading -# those previously-installed .go files, which may be stale, thereby breaking -# the whole thing. -# -# XXX: Use the C locale for when Guile lacks -# . -.scm.go: - $(AM_V_GUILEC)$(MKDIR_P) `dirname "$@"` ; \ - unset GUILE_LOAD_COMPILED_PATH ; \ - LC_ALL=C \ - $(GUILD) compile \ - --load-path="$(top_builddir)/scm" \ - --load-path="$(top_srcdir)/scm" \ - --warn=format --warn=unbound-variable --warn=arity-mismatch \ - --target="$(host)" --output="$@" "$<" - -SUFFIXES = .go -CLEANFILES = $(GOBJECTS) - -# If you're wondering, the configure script keeps deleting all files with a name -# like core.*, so we have to keep re-making it (I lost a good day's work because -# of this). - -core.scm : mcron-core.scm - $(CP) mcron-core.scm core.scm - From 8952d2dc442913f0ecf1fa896d97c882a5daa664 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 17 Oct 2015 20:05:08 +0200 Subject: [PATCH 076/239] build: Support VPATH builds. This allows using 'mcron' before it is installed without hardcoding the local build environment in the executable. * build-aux/pre-inst-env.in: New script. * configure.ac (AC_CONFIG_FILES): Create it. (AC_CONFIG_HEADER): Add 'config.h'. (moduledir): New variable. (PACKAGE_LOAD_PATH): new C preprocessor macro. * mcron.c: Include "config.h". (main): Don't overwrite Guile load paths. (inner_main): Prepend Mcron modules load paths. * Makefile.am (.scm.go, doc/mcron.1): Use 'pre-inst-env'. (mcron_CFLAGS): Remove GUILE_LOAD_PATH macro. (noinst_SCRIPTS): New variable. * .gitignore: Update. --- .gitignore | 4 ++++ Makefile.am | 7 ++++--- build-aux/pre-inst-env.in | 35 +++++++++++++++++++++++++++++++++++ configure.ac | 10 +++++++--- mcron.c | 10 +++++++++- 5 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 build-aux/pre-inst-env.in diff --git a/.gitignore b/.gitignore index 3aa3599..17829a7 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,8 @@ aclocal.m4 autom4te.cache compile config.cache +config.h +config.h.in config.log config.scm config.status @@ -33,4 +35,6 @@ core.scm depcomp install-sh missing +pre-inst-env +stamp-h1 texinfo.tex diff --git a/Makefile.am b/Makefile.am index 8c7b4d0..c2d42b4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,7 +18,7 @@ bin_PROGRAMS = mcron mcron_SOURCES = mcron.c -mcron_CFLAGS = @GUILE_CFLAGS@ -DGUILE_LOAD_PATH=\"$(datadir):./scm:...\" +mcron_CFLAGS = @GUILE_CFLAGS@ mcron_DEPENDENCIES = $(GOBJECTS) # Build Guile modules before linking. mcron_LDADD = @GUILE_LIBS@ @@ -65,13 +65,14 @@ dist_mcronmodule_DATA = \ $(AM_V_GUILEC)$(MKDIR_P) `dirname "$@"` ; \ unset GUILE_LOAD_COMPILED_PATH ; \ LC_ALL=C \ - $(GUILD) compile \ + $(top_builddir)/pre-inst-env $(GUILD) compile \ --load-path="$(top_builddir)/scm" \ --load-path="$(top_srcdir)/scm" \ --warn=format --warn=unbound-variable --warn=arity-mismatch \ --target="$(host)" --output="$@" "$<" SUFFIXES = .go +noinst_SCRIPTS = pre-inst-env dist-hook: gen-ChangeLog @@ -128,7 +129,7 @@ dist_man_MANS = doc/mcron.1 # elemental man page. Will only work once the mcron program is installed. doc/mcron.1: mcron.c -$(AM_V_HELP2MAN)$(MKDIR_P) `dirname "$@"` ; \ - $(HELP2MAN) \ + $(top_builddir)/pre-inst-env $(HELP2MAN) \ -n 'a program to run tasks at regular (or not) intervals' \ ./mcron > $@ diff --git a/build-aux/pre-inst-env.in b/build-aux/pre-inst-env.in new file mode 100644 index 0000000..7e69b44 --- /dev/null +++ b/build-aux/pre-inst-env.in @@ -0,0 +1,35 @@ +#!/bin/sh + +# Copyright © 2015, 2016 Mathieu Lirzin +# +# This file is part of GNU Mcron. +# +# GNU Mcron is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNU Mcron is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Mcron. If not, see . + +abs_top_srcdir="`cd "@abs_top_srcdir@" > /dev/null; pwd`" +abs_top_builddir="`cd "@abs_top_builddir@" > /dev/null; pwd`" + +GUILE_LOAD_COMPILED_PATH="$abs_top_builddir/scm${GUILE_LOAD_COMPILED_PATH:+:}$GUILE_LOAD_COMPILED_PATH" +GUILE_LOAD_PATH="$abs_top_builddir/scm:$abs_top_srcdir/scm${GUILE_LOAD_PATH:+:}:$GUILE_LOAD_PATH" +export GUILE_LOAD_COMPILED_PATH GUILE_LOAD_PATH + +PATH="$abs_top_builddir:$PATH" +export PATH + +# Define $MCRON_UNINSTALLED to prevent 'mcron' from prepending @moduledir@ to +# the Guile load paths. +MCRON_UNINSTALLED=1 +export MCRON_UNINSTALLED + +exec "$@" diff --git a/configure.ac b/configure.ac index 9972ad5..d6262f2 100644 --- a/configure.ac +++ b/configure.ac @@ -23,13 +23,15 @@ AC_PREREQ(2.61) AC_INIT([GNU Mcron], [1.0.8], [bug-mcron@gnu.org]) +AC_CONFIG_HEADER([config.h]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([subdir-objects]) AM_SILENT_RULES([yes]) # enables silent rules by default -mcronmoduledir="${datarootdir}/guile/site/2.0/mcron" -AC_SUBST([mcronmoduledir]) - +moduledir="${datarootdir}/guile/site/2.0" +AC_SUBST([mcronmoduledir], ["${moduledir}/mcron"]) +AC_DEFINE_UNQUOTED([PACKAGE_LOAD_PATH], ["${moduledir}"], + [Define to the guile modules location of this package.]) AC_MSG_CHECKING([whether debugging is requested]) AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], @@ -181,6 +183,8 @@ AC_SUBST(CONFIG_TMP_DIR) real_program_prefix=`echo $program_prefix | sed s/NONE//` AC_SUBST(real_program_prefix) +AC_CONFIG_FILES([pre-inst-env:build-aux/pre-inst-env.in], + [chmod +x pre-inst-env]) AC_CONFIG_FILES([doc/config.texi Makefile scm/mcron/config.scm]) diff --git a/mcron.c b/mcron.c index 0c62ec8..92e1a37 100644 --- a/mcron.c +++ b/mcron.c @@ -22,6 +22,7 @@ is needed because the crontab personality requires SUID which is not permitted for executable scripts. */ +#include "config.h" #include #include #include @@ -35,7 +36,6 @@ static SCM set_cron_signals (void); int main (int argc, char **argv) { - setenv ("GUILE_LOAD_PATH", GUILE_LOAD_PATH, 1); scm_boot_guile (argc, argv, inner_main, 0); return EXIT_SUCCESS; @@ -45,6 +45,14 @@ main (int argc, char **argv) static void inner_main (void *closure, int argc, char **argv) { + /* Set Guile load paths to ensure that Mcron modules will be found. */ + if (getenv ("MCRON_UNINSTALLED") == NULL) + { + scm_c_eval_string ("(set! %load-path (cons \"" + PACKAGE_LOAD_PATH "\" %load-path))"); + scm_c_eval_string ("(set! %load-compiled-path (cons \"" + PACKAGE_LOAD_PATH "\" %load-compiled-path))"); + } scm_set_current_module (scm_c_resolve_module ("mcron main")); /* Register set_cron_signals to be called from Guile. */ scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); From ce0d72ec8319a6a67d3fc4cb8a855ed75d18d514 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 17 Oct 2015 21:32:46 +0200 Subject: [PATCH 077/239] build: Fix 'distcheck' target failures. * Makefile.am (TEXI2DVI, DISTCLEANFILES, doc_mcron_TEXINFOS) (nodist_doc_mcron_TEXINFOS): New variables. This fixes the build of the dvi/pdf documentation. --- Makefile.am | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Makefile.am b/Makefile.am index c2d42b4..b6c325b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -116,6 +116,7 @@ uninstall-hook: EXTRA_DIST = BUGS CLEANFILES = $(GOBJECTS) +DISTCLEANFILES = $(GEN_MODULES) ## --------------- ## ## Documentation. ## @@ -123,8 +124,13 @@ CLEANFILES = $(GOBJECTS) info_TEXINFOS = doc/mcron.texi doc_mcron_TEXINFOS = doc/fdl.texi +nodist_doc_mcron_TEXINFOS = doc/config.texi dist_man_MANS = doc/mcron.1 +# XXX: Allow the inclusion of 'doc/fdl.texi' and 'doc/config.texi' inside +# 'doc/mcron.texi' for 'dvi' and 'pdf' targets. +TEXI2DVI = texi2dvi -I doc + # Not part of formal package building, but a rule for manual use to get the # elemental man page. Will only work once the mcron program is installed. doc/mcron.1: mcron.c From 5da0024b934513aa76a2cb32dc8f6cb00370262a Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 20 Apr 2016 02:53:22 +0200 Subject: [PATCH 078/239] job-specifier: Rewrite 'range' procedure. * scm/mcron/job-specifier.scm (range): Use 'unfold'. --- scm/mcron/job-specifier.scm | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/scm/mcron/job-specifier.scm b/scm/mcron/job-specifier.scm index 1647ede..3f73b82 100644 --- a/scm/mcron/job-specifier.scm +++ b/scm/mcron/job-specifier.scm @@ -1,4 +1,5 @@ ;; Copyright (C) 2003 Dale Mellor +;; Copyright (C) 2016 Mathieu Lirzin ;; ;; This file is part of GNU mcron. ;; @@ -37,26 +38,16 @@ #:use-module (mcron core) #:use-module (mcron environment) #:use-module (mcron vixie-time) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) #:re-export (append-environment-mods)) - -;; Function (available to user configuration files) which produces a list of -;; values from start up to (but not including) end. An optional step may be -;; supplied, and (if positive) only every step'th value will go into the -;; list. For example, (range 1 6 2) returns '(1 3 5). - -(define (range start end . step) - (let ((step (if (or (null? step) - (<= (car step) 0)) - 1 - (car step)))) - (let loop ((start start)) - (if (>= start end) '() - (cons start - (loop (+ start step))))))) - - +(define* (range start end #:optional (step 1)) + "Produces a list of values from START up to (but not including) END. An +optional STEP may be supplied, and (if positive) only every step'th value will +go into the list. For example, (range 1 6 2) returns '(1 3 5)." + (unfold (cut >= <> end) identity (cute + <> (max step 1)) start)) ;; Internal function (not supposed to be used directly in configuration files; ;; it is exported from the module for the convenience of other parts of the From 5097e30babe31a40a3fb8e281fee2a472414e5f8 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 20 Apr 2016 04:31:52 +0200 Subject: [PATCH 079/239] job-specifier: Add '%find-best-next' procedure. * scm/mcron/job-specifier.scm (find-best-next): Rename to ... (%find-best-next): ... this. Rewrite it using a functional style. All callers changed. --- scm/mcron/job-specifier.scm | 50 ++++++++++++++++--------------------- scm/mcron/vixie-time.scm | 25 +++++++++---------- 2 files changed, 33 insertions(+), 42 deletions(-) diff --git a/scm/mcron/job-specifier.scm b/scm/mcron/job-specifier.scm index 3f73b82..1c2f9d9 100644 --- a/scm/mcron/job-specifier.scm +++ b/scm/mcron/job-specifier.scm @@ -24,6 +24,13 @@ ;; add-job function), and the procedure for declaring environment modifications. (define-module (mcron job-specifier) + #:use-module (ice-9 match) + #:use-module (mcron core) + #:use-module (mcron environment) + #:use-module (mcron vixie-time) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) + #:re-export (append-environment-mods) #:export (range next-year-from next-year next-month-from next-month @@ -33,15 +40,7 @@ next-second-from next-second set-configuration-user set-configuration-time - job - find-best-next) - #:use-module (mcron core) - #:use-module (mcron environment) - #:use-module (mcron vixie-time) - #:use-module (srfi srfi-1) - #:use-module (srfi srfi-26) - #:re-export (append-environment-mods)) - + job)) (define* (range start end #:optional (step 1)) "Produces a list of values from START up to (but not including) END. An @@ -49,25 +48,18 @@ optional STEP may be supplied, and (if positive) only every step'th value will go into the list. For example, (range 1 6 2) returns '(1 3 5)." (unfold (cut >= <> end) identity (cute + <> (max step 1)) start)) -;; Internal function (not supposed to be used directly in configuration files; -;; it is exported from the module for the convenience of other parts of the -;; mcron implementation) which takes a value and a list of possible next values -;; (all assumed less than 9999). It returns a pair consisting of the smallest -;; element of the list, and the smallest element larger than the current -;; value. If an example of the latter cannot be found, 9999 will be returned. - -(define (find-best-next current next-list) - (let ((current-best (cons 9999 9999))) - (for-each (lambda (allowed-time) - (if (< allowed-time (car current-best)) - (set-car! current-best allowed-time)) - (if (and (> allowed-time current) - (< allowed-time (cdr current-best))) - (set-cdr! current-best allowed-time))) - next-list) - current-best)) - - +(define (%find-best-next current next-list) + ;; Takes a value and a list of possible next values (all assumed less than + ;; 9999). It returns a pair consisting of the smallest element of the + ;; NEXT-LIST, and the smallest element larger than the CURRENT value. If an + ;; example of the latter cannot be found, 9999 will be returned. + (let loop ((smallest 9999) (closest+ 9999) (lst next-list)) + (match lst + (() (cons smallest closest+)) + ((time . rest) + (loop (min time smallest) + (if (> time current) (min time closest+) closest+) + rest))))) ;; Internal function to return the time corresponding to some near future ;; hour. If hour-list is not supplied, the time returned corresponds to the @@ -89,7 +81,7 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." set-component! set-higher-component!) (if (null? value-list) (set-component! time (+ (component time) 1)) - (let ((best-next (find-best-next (component time) (car value-list)))) + (let ((best-next (%find-best-next (component time) (car value-list)))) (if (eqv? 9999 (cdr best-next)) (begin (set-higher-component! time (+ (higher-component time) 1)) diff --git a/scm/mcron/vixie-time.scm b/scm/mcron/vixie-time.scm index 2f26a6d..a91fa89 100644 --- a/scm/mcron/vixie-time.scm +++ b/scm/mcron/vixie-time.scm @@ -15,15 +15,13 @@ ;; You should have received a copy of the GNU General Public License along ;; with GNU mcron. If not, see . - (define-module (mcron vixie-time) - #:export (parse-vixie-time) - #:use-module (mcron job-specifier)) - - -(use-modules (srfi srfi-1) (srfi srfi-13) (srfi srfi-14) - (ice-9 regex)) - + #:use-module (ice-9 regex) + #:use-module (mcron job-specifier) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-13) + #:use-module (srfi srfi-14) + #:export (parse-vixie-time)) ;; In Vixie-style time specifications three-letter symbols are allowed to stand ;; for the numbers corresponding to months and days of the week. We deal with @@ -179,11 +177,12 @@ ;; simply unreadable without all of these aliases. (define (increment-time-component time time-spec) - (let* ((time-list (time-spec:list time-spec)) - (getter (time-spec:getter time-spec)) - (setter (time-spec:setter time-spec)) - (next-best (find-best-next (getter time) time-list)) - (wrap-around (eqv? (cdr next-best) 9999))) + (let* ((time-list (time-spec:list time-spec)) + (getter (time-spec:getter time-spec)) + (setter (time-spec:setter time-spec)) + (find-best-next (@@ (mcron job-specifier) %find-best-next)) + (next-best (find-best-next (getter time) time-list)) + (wrap-around (eqv? (cdr next-best) 9999))) (setter time ((if wrap-around car cdr) next-best)) wrap-around)) From bb8703b679509fe3b842f9f24f6871b3c2889916 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 4 May 2016 16:06:02 +0200 Subject: [PATCH 080/239] build: Do not auto-compile 'guild'. * Makefile.am (.scm.go): Set GUILE_AUTO_COMPILE to 0. --- Makefile.am | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index b6c325b..4f11c0f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -57,13 +57,14 @@ dist_mcronmodule_DATA = \ # in there that are newer than the local .scm files (for instance because the # user ran 'make install' recently). When that happens, we end up loading # those previously-installed .go files, which may be stale, thereby breaking -# the whole thing. +# the whole thing. Set GUILE_AUTO_COMPILE to 0 to avoid auto-compiling guild +# as a consequence of the previous hack. # # XXX: Use the C locale for when Guile lacks # . .scm.go: $(AM_V_GUILEC)$(MKDIR_P) `dirname "$@"` ; \ - unset GUILE_LOAD_COMPILED_PATH ; \ + export GUILE_AUTO_COMPILE=0 ; unset GUILE_LOAD_COMPILED_PATH ; \ LC_ALL=C \ $(top_builddir)/pre-inst-env $(GUILD) compile \ --load-path="$(top_builddir)/scm" \ From 995bc9ca6ebf6880d7e7e6f3d1baa2941758fc47 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 7 May 2016 11:09:44 +0200 Subject: [PATCH 081/239] all: Rename 'scm' directory to 'src'. * scm/mcron/config.scm.in: Rename to ... * src/mcron/config.scm.in: ... this. * scm/mcron/crontab.scm: Rename to ... * src/mcron/crontab.scm: ... this. * scm/mcron/environment.scm: Rename to ... * src/mcron/environment.scm: ... this. * scm/mcron/job-specifier.scm: Rename to ... * src/mcron/job-specifier.scm: ... this. * scm/mcron/main.scm: Rename to ... * src/mcron/main.scm: ... this. * scm/mcron/mcron-core.scm: Rename to ... * src/mcron/mcron-core.scm: ... this. * scm/mcron/redirect.scm: Rename to ... * src/mcron/redirect.scm: ... this. * scm/mcron/vixie-specification.scm: Rename to ... * src/mcron/vixie-specification.scm: ... this. * scm/mcron/vixie-time.scm: Rename to ... * src/mcron/vixie-time.scm: ... this. * mcron.c: Rename to ... * src/mcron.c: ... this. * Makefile.am: Adapt to them. * build-aux/pre-inst-env.in: Likewise. * configure.ac (AC_CONFIG_FILES): Likewise. (AC_CONFIG_HEADER): Set to 'src/config.h'. * .gitignore: Update. --- .gitignore | 2 +- Makefile.am | 30 +++++++++++----------- build-aux/pre-inst-env.in | 4 +-- configure.ac | 4 +-- mcron.c => src/mcron.c | 0 {scm => src}/mcron/config.scm.in | 0 {scm => src}/mcron/crontab.scm | 0 {scm => src}/mcron/environment.scm | 0 {scm => src}/mcron/job-specifier.scm | 0 {scm => src}/mcron/main.scm | 0 {scm => src}/mcron/mcron-core.scm | 0 {scm => src}/mcron/redirect.scm | 0 {scm => src}/mcron/vixie-specification.scm | 0 {scm => src}/mcron/vixie-time.scm | 0 14 files changed, 20 insertions(+), 20 deletions(-) rename mcron.c => src/mcron.c (100%) rename {scm => src}/mcron/config.scm.in (100%) rename {scm => src}/mcron/crontab.scm (100%) rename {scm => src}/mcron/environment.scm (100%) rename {scm => src}/mcron/job-specifier.scm (100%) rename {scm => src}/mcron/main.scm (100%) rename {scm => src}/mcron/mcron-core.scm (100%) rename {scm => src}/mcron/redirect.scm (100%) rename {scm => src}/mcron/vixie-specification.scm (100%) rename {scm => src}/mcron/vixie-time.scm (100%) diff --git a/.gitignore b/.gitignore index 17829a7..8bffc85 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.o *~ .deps +.dirstamp /build-aux/compile /build-aux/config.guess /build-aux/config.sub @@ -10,7 +11,6 @@ /build-aux/mdate-sh /build-aux/missing /build-aux/texinfo.tex -/doc/.dirstamp /doc/config.texi /doc/mcron.1 /doc/mcron.info diff --git a/Makefile.am b/Makefile.am index 4f11c0f..1b5317c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,26 +17,26 @@ # along with this program. If not, see . bin_PROGRAMS = mcron -mcron_SOURCES = mcron.c +mcron_SOURCES = src/mcron.c mcron_CFLAGS = @GUILE_CFLAGS@ mcron_DEPENDENCIES = $(GOBJECTS) # Build Guile modules before linking. mcron_LDADD = @GUILE_LIBS@ MODULES = \ - scm/mcron/environment.scm \ - scm/mcron/job-specifier.scm \ - scm/mcron/main.scm \ - scm/mcron/redirect.scm \ - scm/mcron/vixie-specification.scm \ - scm/mcron/vixie-time.scm + src/mcron/environment.scm \ + src/mcron/job-specifier.scm \ + src/mcron/main.scm \ + src/mcron/redirect.scm \ + src/mcron/vixie-specification.scm \ + src/mcron/vixie-time.scm GEN_MODULES = \ - scm/mcron/config.scm \ - scm/mcron/core.scm + src/mcron/config.scm \ + src/mcron/core.scm CP = @CP@ # XXX: Prevent the 'configure' script to delete the 'core.*' files. -scm/mcron/core.scm: scm/mcron/mcron-core.scm +src/mcron/core.scm: src/mcron/mcron-core.scm $(CP) $< $@ GOBJECTS = \ @@ -49,8 +49,8 @@ mcronmodule_DATA = \ dist_mcronmodule_DATA = \ $(MODULES) \ - scm/mcron/crontab.scm \ - scm/mcron/mcron-core.scm + src/mcron/crontab.scm \ + src/mcron/mcron-core.scm # Unset 'GUILE_LOAD_COMPILED_PATH' altogether while compiling. Otherwise, if # $GUILE_LOAD_COMPILED_PATH contains $(mcronmoduledir), we may find .go files @@ -67,8 +67,8 @@ dist_mcronmodule_DATA = \ export GUILE_AUTO_COMPILE=0 ; unset GUILE_LOAD_COMPILED_PATH ; \ LC_ALL=C \ $(top_builddir)/pre-inst-env $(GUILD) compile \ - --load-path="$(top_builddir)/scm" \ - --load-path="$(top_srcdir)/scm" \ + --load-path="$(top_builddir)/src" \ + --load-path="$(top_srcdir)/src" \ --warn=format --warn=unbound-variable --warn=arity-mismatch \ --target="$(host)" --output="$@" "$<" @@ -134,7 +134,7 @@ TEXI2DVI = texi2dvi -I doc # Not part of formal package building, but a rule for manual use to get the # elemental man page. Will only work once the mcron program is installed. -doc/mcron.1: mcron.c +doc/mcron.1: src/mcron.c -$(AM_V_HELP2MAN)$(MKDIR_P) `dirname "$@"` ; \ $(top_builddir)/pre-inst-env $(HELP2MAN) \ -n 'a program to run tasks at regular (or not) intervals' \ diff --git a/build-aux/pre-inst-env.in b/build-aux/pre-inst-env.in index 7e69b44..ea866ee 100644 --- a/build-aux/pre-inst-env.in +++ b/build-aux/pre-inst-env.in @@ -20,8 +20,8 @@ abs_top_srcdir="`cd "@abs_top_srcdir@" > /dev/null; pwd`" abs_top_builddir="`cd "@abs_top_builddir@" > /dev/null; pwd`" -GUILE_LOAD_COMPILED_PATH="$abs_top_builddir/scm${GUILE_LOAD_COMPILED_PATH:+:}$GUILE_LOAD_COMPILED_PATH" -GUILE_LOAD_PATH="$abs_top_builddir/scm:$abs_top_srcdir/scm${GUILE_LOAD_PATH:+:}:$GUILE_LOAD_PATH" +GUILE_LOAD_COMPILED_PATH="$abs_top_builddir/src${GUILE_LOAD_COMPILED_PATH:+:}$GUILE_LOAD_COMPILED_PATH" +GUILE_LOAD_PATH="$abs_top_builddir/src:$abs_top_srcdir/src${GUILE_LOAD_PATH:+:}:$GUILE_LOAD_PATH" export GUILE_LOAD_COMPILED_PATH GUILE_LOAD_PATH PATH="$abs_top_builddir:$PATH" diff --git a/configure.ac b/configure.ac index d6262f2..175ba16 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ AC_PREREQ(2.61) AC_INIT([GNU Mcron], [1.0.8], [bug-mcron@gnu.org]) -AC_CONFIG_HEADER([config.h]) +AC_CONFIG_HEADER([src/config.h]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([subdir-objects]) AM_SILENT_RULES([yes]) # enables silent rules by default @@ -187,5 +187,5 @@ AC_CONFIG_FILES([pre-inst-env:build-aux/pre-inst-env.in], [chmod +x pre-inst-env]) AC_CONFIG_FILES([doc/config.texi Makefile - scm/mcron/config.scm]) + src/mcron/config.scm]) AC_OUTPUT diff --git a/mcron.c b/src/mcron.c similarity index 100% rename from mcron.c rename to src/mcron.c diff --git a/scm/mcron/config.scm.in b/src/mcron/config.scm.in similarity index 100% rename from scm/mcron/config.scm.in rename to src/mcron/config.scm.in diff --git a/scm/mcron/crontab.scm b/src/mcron/crontab.scm similarity index 100% rename from scm/mcron/crontab.scm rename to src/mcron/crontab.scm diff --git a/scm/mcron/environment.scm b/src/mcron/environment.scm similarity index 100% rename from scm/mcron/environment.scm rename to src/mcron/environment.scm diff --git a/scm/mcron/job-specifier.scm b/src/mcron/job-specifier.scm similarity index 100% rename from scm/mcron/job-specifier.scm rename to src/mcron/job-specifier.scm diff --git a/scm/mcron/main.scm b/src/mcron/main.scm similarity index 100% rename from scm/mcron/main.scm rename to src/mcron/main.scm diff --git a/scm/mcron/mcron-core.scm b/src/mcron/mcron-core.scm similarity index 100% rename from scm/mcron/mcron-core.scm rename to src/mcron/mcron-core.scm diff --git a/scm/mcron/redirect.scm b/src/mcron/redirect.scm similarity index 100% rename from scm/mcron/redirect.scm rename to src/mcron/redirect.scm diff --git a/scm/mcron/vixie-specification.scm b/src/mcron/vixie-specification.scm similarity index 100% rename from scm/mcron/vixie-specification.scm rename to src/mcron/vixie-specification.scm diff --git a/scm/mcron/vixie-time.scm b/src/mcron/vixie-time.scm similarity index 100% rename from scm/mcron/vixie-time.scm rename to src/mcron/vixie-time.scm From 52364699ed36e53ef5f913f1511f6a8e182e80ed Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 7 May 2016 11:44:13 +0200 Subject: [PATCH 082/239] build: Use AC_CONFIG_SRCDIR safety check. * configure.ac (AC_CONFIG_SCRDIR): Set it to 'src/mcron.c'. --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 175ba16..c6c77d9 100644 --- a/configure.ac +++ b/configure.ac @@ -24,6 +24,7 @@ AC_PREREQ(2.61) AC_INIT([GNU Mcron], [1.0.8], [bug-mcron@gnu.org]) AC_CONFIG_HEADER([src/config.h]) +AC_CONFIG_SRCDIR([src/mcron.c]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([subdir-objects]) AM_SILENT_RULES([yes]) # enables silent rules by default From 418b81e1af8d18c86693cb43ffe89354af28e3a8 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 7 May 2016 13:08:06 +0200 Subject: [PATCH 083/239] base: Rename (mcron core) module to (mcron base). The 'configure' script deletes the 'core.*' files. Having a file named 'base.scm' instead of 'core.scm' simplifies the build process without changing the semantics. * src/mcron/mcron-core.scm: Rename to ... * src/mcron/base.scm: ... this. All module users changed. * Makefile.am (MODULES): Add 'src/mcron/base.scm'. (CP): Remove variable. (src/mcron/core.scm): Remove target. (GEN_MODULES): Remove 'src/mcron/core.scm'. (dist_mcronmodule_DATA): Remove 'src/mcron/mcron-core.scm' * doc/mcron.texi: Adapt to name change. * .gitignore: Update. --- .gitignore | 1 - Makefile.am | 12 +++--------- doc/mcron.texi | 24 ++++++++++++------------ src/mcron/{mcron-core.scm => base.scm} | 2 +- src/mcron/job-specifier.scm | 7 ++++--- src/mcron/main.scm | 4 ++-- src/mcron/vixie-specification.scm | 2 +- 7 files changed, 23 insertions(+), 29 deletions(-) rename src/mcron/{mcron-core.scm => base.scm} (99%) diff --git a/.gitignore b/.gitignore index 8bffc85..c064be1 100644 --- a/.gitignore +++ b/.gitignore @@ -31,7 +31,6 @@ config.log config.scm config.status configure -core.scm depcomp install-sh missing diff --git a/Makefile.am b/Makefile.am index 1b5317c..f02b84e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,6 +23,7 @@ mcron_DEPENDENCIES = $(GOBJECTS) # Build Guile modules before linking. mcron_LDADD = @GUILE_LIBS@ MODULES = \ + src/mcron/base.scm \ src/mcron/environment.scm \ src/mcron/job-specifier.scm \ src/mcron/main.scm \ @@ -31,13 +32,7 @@ MODULES = \ src/mcron/vixie-time.scm GEN_MODULES = \ - src/mcron/config.scm \ - src/mcron/core.scm - -CP = @CP@ -# XXX: Prevent the 'configure' script to delete the 'core.*' files. -src/mcron/core.scm: src/mcron/mcron-core.scm - $(CP) $< $@ + src/mcron/config.scm GOBJECTS = \ $(GEN_MODULES:%.scm=%.go) \ @@ -49,8 +44,7 @@ mcronmodule_DATA = \ dist_mcronmodule_DATA = \ $(MODULES) \ - src/mcron/crontab.scm \ - src/mcron/mcron-core.scm + src/mcron/crontab.scm # Unset 'GUILE_LOAD_COMPILED_PATH' altogether while compiling. Otherwise, if # $GUILE_LOAD_COMPILED_PATH contains $(mcronmoduledir), we may find .go files diff --git a/doc/mcron.texi b/doc/mcron.texi index 27cd1b7..340faca 100644 --- a/doc/mcron.texi +++ b/doc/mcron.texi @@ -104,7 +104,7 @@ Detailed invoking Guile modules -* The core module:: The job list and execution loop. +* The base module:: The job list and execution loop. * The redirect module:: Sending output of jobs to a mail box. * The vixie-time module:: Parsing vixie-style time specifications. * The job-specifier module:: All commands for scheme configuration files. @@ -327,7 +327,7 @@ taken to be program code made up of the functions @code{(next-second . args)}, @code{(next-minute...)}, etc, where the optional arguments can be supplied with the @code{(range)} function above (these functions are analogous to the ones above except that they implicitly -assume the current time; it is supplied by the mcron core when the +assume the current time; it is supplied by the mcron base when the list is eval'd). @cindex time specification @@ -1150,26 +1150,26 @@ non-absolute time specified on the Gregorian calendar (the first day of next week, for example). Finally, it may be the wish of the user to provide a program with the functionality of mcron plus a bit extra. -The core module maintains mcron's internal job lists, and provides the +The base module maintains mcron's internal job lists, and provides the main wait-run-wait loop that is mcron's main function. It also introduces the facilities for accumulating a set of environment modifiers, which take effect when jobs run. @menu -* The core module:: The job list and execution loop. +* The base module:: The job list and execution loop. * The redirect module:: Sending output of jobs to a mail box. * The vixie-time module:: Parsing vixie-style time specifications. * The job-specifier module:: All commands for scheme configuration files. * The vixie-specification module:: Commands for reading vixie-style crontabs. @end menu -@node The core module, The redirect module, Guile modules, Guile modules -@section The core module +@node The base module, The redirect module, Guile modules, Guile modules +@section The base module @cindex guile module -@cindex core module -@cindex modules, core +@cindex base module +@cindex modules, base -This module may be used by including @code{(use-modules (mcron core))} +This module may be used by including @code{(use-modules (mcron base))} in a program. The main functions are @code{add-job} and @code{run-job-loop}, which allow a program to create a list of job specifications to run, and then to initiate the wait-run-wait loop @@ -1221,7 +1221,7 @@ becoming available for reading on one of the file descriptors in the fd-list, if supplied. Only in this case will the procedure return to the calling program, which may then make modifications to the job list before calling the @code{run-job-loop} procedure again to resume execution of -the mcron core. +the mcron base. @end deffn @deffn{Scheme procedure} remove-user-jobs user @@ -1242,7 +1242,7 @@ last job that was reported in the schedule report. The report itself is returned to the calling program as a string. @end deffn -@node The redirect module, The vixie-time module, The core module, Guile modules +@node The redirect module, The vixie-time module, The base module, Guile modules @section The redirect module @cindex redirect module @cindex modules, redirect @@ -1263,7 +1263,7 @@ vixie-time))}. This module provides a single method for converting a vixie-style time specification into a procedure which can be used as the -@code{next-time-function} to the core @code{add-job} procedure, or to +@code{next-time-function} to the base @code{add-job} procedure, or to the @code{job-specifier} @code{job} procedure. See @ref{Vixie Syntax} for full details of the allowed format for the time string. diff --git a/src/mcron/mcron-core.scm b/src/mcron/base.scm similarity index 99% rename from src/mcron/mcron-core.scm rename to src/mcron/base.scm index 13781c9..7094dbc 100644 --- a/src/mcron/mcron-core.scm +++ b/src/mcron/base.scm @@ -18,7 +18,7 @@ -(define-module (mcron core) +(define-module (mcron base) #:use-module (mcron environment) #:use-module (srfi srfi-9) #:export (add-job diff --git a/src/mcron/job-specifier.scm b/src/mcron/job-specifier.scm index 1c2f9d9..9e13551 100644 --- a/src/mcron/job-specifier.scm +++ b/src/mcron/job-specifier.scm @@ -20,12 +20,13 @@ ;; This module defines all the functions that can be used by scheme mcron ;; configuration files, namely the procedures for working out next times, the -;; job procedure for registering new jobs (actually a wrapper around the core -;; add-job function), and the procedure for declaring environment modifications. +;; job procedure for registering new jobs (actually a wrapper around the +;; base add-job function), and the procedure for declaring environment +;; modifications. (define-module (mcron job-specifier) #:use-module (ice-9 match) - #:use-module (mcron core) + #:use-module (mcron base) #:use-module (mcron environment) #:use-module (mcron vixie-time) #:use-module (srfi srfi-1) diff --git a/src/mcron/main.scm b/src/mcron/main.scm index 1f2b068..db7dfd6 100644 --- a/src/mcron/main.scm +++ b/src/mcron/main.scm @@ -25,7 +25,7 @@ #:use-module (ice-9 rdelim) #:use-module (ice-9 regex) #:use-module (mcron config) - #:use-module (mcron core) + #:use-module (mcron base) #:use-module (mcron job-specifier) #:use-module (mcron vixie-specification) #:use-module (srfi srfi-2) @@ -389,7 +389,7 @@ option.\n") (lambda () (display (getpid)) (newline))))) ;; Now the main loop. Forever execute the run-job-loop procedure in the - ;; mcron core, and when it drops out (can only be because a message has come + ;; mcron base, and when it drops out (can only be because a message has come ;; in on the socket) we process the socket request before restarting the ;; loop again. Sergey Poznyakoff: we can also drop out of run-job-loop ;; because of a SIGCHLD, so must test FDES-LIST. diff --git a/src/mcron/vixie-specification.scm b/src/mcron/vixie-specification.scm index 5cd1528..f055383 100644 --- a/src/mcron/vixie-specification.scm +++ b/src/mcron/vixie-specification.scm @@ -30,7 +30,7 @@ read-vixie-file check-system-crontab) #:use-module ((mcron config) :select (config-socket-file)) - #:use-module (mcron core) + #:use-module (mcron base) #:use-module (mcron job-specifier) #:use-module (mcron redirect) #:use-module (mcron vixie-time)) From bca16da45194df8778f9d1711baa9962f7742fec Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 7 May 2016 13:58:50 +0200 Subject: [PATCH 084/239] build: Remove GOBJECTS and GEN_MODULES variables. * Makefile.am (GOBJECTS, GEN_MODULES): Remove variables. (mcronmodule_DATA, DISTCLEANFILES): Inline their contents. (mcron_DEPENDENCIES, CLEANFILES): Use 'mcronmodule_DATA'. --- Makefile.am | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/Makefile.am b/Makefile.am index f02b84e..a7baef3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,7 +19,7 @@ bin_PROGRAMS = mcron mcron_SOURCES = src/mcron.c mcron_CFLAGS = @GUILE_CFLAGS@ -mcron_DEPENDENCIES = $(GOBJECTS) # Build Guile modules before linking. +mcron_DEPENDENCIES = $(mcronmodule_DATA) mcron_LDADD = @GUILE_LIBS@ MODULES = \ @@ -31,16 +31,9 @@ MODULES = \ src/mcron/vixie-specification.scm \ src/mcron/vixie-time.scm -GEN_MODULES = \ - src/mcron/config.scm - -GOBJECTS = \ - $(GEN_MODULES:%.scm=%.go) \ - $(MODULES:%.scm=%.go) - mcronmodule_DATA = \ - $(GOBJECTS) \ - $(GEN_MODULES) + $(MODULES:%.scm=%.go) \ + src/mcron/config.go dist_mcronmodule_DATA = \ $(MODULES) \ @@ -110,8 +103,8 @@ uninstall-hook: fi EXTRA_DIST = BUGS -CLEANFILES = $(GOBJECTS) -DISTCLEANFILES = $(GEN_MODULES) +CLEANFILES = $(mcronmodule_DATA) +DISTCLEANFILES = src/config.scm ## --------------- ## ## Documentation. ## From 0d91ec1b974679596631da17539429a46ca4cad3 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 7 May 2016 16:01:02 +0200 Subject: [PATCH 085/239] build: Use lowercase names for local variables. This helps distinguish variable names with a special Automake semantic. * Makefile.am (MODULES): Rename to ... (modules): ... this. (mcronmodule_DATA, dist_mcronmodule_DATA): Adapt to it. --- Makefile.am | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Makefile.am b/Makefile.am index a7baef3..e486db3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,21 +22,21 @@ mcron_CFLAGS = @GUILE_CFLAGS@ mcron_DEPENDENCIES = $(mcronmodule_DATA) mcron_LDADD = @GUILE_LIBS@ -MODULES = \ - src/mcron/base.scm \ - src/mcron/environment.scm \ - src/mcron/job-specifier.scm \ - src/mcron/main.scm \ - src/mcron/redirect.scm \ - src/mcron/vixie-specification.scm \ +modules = \ + src/mcron/base.scm \ + src/mcron/environment.scm \ + src/mcron/job-specifier.scm \ + src/mcron/main.scm \ + src/mcron/redirect.scm \ + src/mcron/vixie-specification.scm \ src/mcron/vixie-time.scm -mcronmodule_DATA = \ - $(MODULES:%.scm=%.go) \ +mcronmodule_DATA = \ + $(modules:%.scm=%.go) \ src/mcron/config.go -dist_mcronmodule_DATA = \ - $(MODULES) \ +dist_mcronmodule_DATA = \ + $(modules) \ src/mcron/crontab.scm # Unset 'GUILE_LOAD_COMPILED_PATH' altogether while compiling. Otherwise, if From 45b062490a9924bcc6d582d10061244ced73f3f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Sat, 7 May 2016 16:33:01 +0200 Subject: [PATCH 086/239] base: run-jobs: Ensure that the child process always terminates. * src/mcron/base.scm (run-jobs): Use 'dynamic-wind' instead of 'begin'. --- src/mcron/base.scm | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/mcron/base.scm b/src/mcron/base.scm index 7094dbc..aae5fe5 100644 --- a/src/mcron/base.scm +++ b/src/mcron/base.scm @@ -1,3 +1,4 @@ +;; Copyright (C) 2016 Ludovic Courtès ;; Copyright (C) 2015, 2016 Mathieu Lirzin ;; Copyright (C) 2003 Dale Mellor ;; @@ -198,13 +199,16 @@ (for-each (lambda (job) (if (eqv? (primitive-fork) 0) - (begin - (setgid (passwd:gid (job:user job))) - (setuid (passwd:uid (job:user job))) - (chdir (passwd:dir (job:user job))) - (modify-environment (job:environment job) (job:user job)) - ((job:action job)) - (primitive-exit 0)) + (dynamic-wind + (const #t) + (lambda () + (setgid (passwd:gid (job:user job))) + (setuid (passwd:uid (job:user job))) + (chdir (passwd:dir (job:user job))) + (modify-environment (job:environment job) (job:user job)) + ((job:action job))) + (lambda () + (primitive-exit 0))) (begin (set! number-children (+ number-children 1)) (job:next-time-set! job ((job:next-time-function job) From 31baff1a5187d8ddc89324cbe42dbeffc309c962 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 7 May 2016 18:51:49 +0200 Subject: [PATCH 087/239] job-specifier: job: Add #:user keyword argument. * src/mcron/job-specifier.scm (job): Add #:user keyword argument. * doc/mcron.texi (Job specification): Document it. --- doc/mcron.texi | 25 +++++++++++++------------ src/mcron/job-specifier.scm | 12 ++++++++---- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/doc/mcron.texi b/doc/mcron.texi index 340faca..a59505d 100644 --- a/doc/mcron.texi +++ b/doc/mcron.texi @@ -271,11 +271,13 @@ on your system, as root. @cindex guile syntax @cindex syntax, guile @findex job -In Guile-formatted configuration files each command that needs -executing is introduced with the @code{job} function. This function -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. +In Guile-formatted configuration files each command that needs executing is +introduced with the @code{job} function. This function 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. Additionally a @var{user} keyword +argument can be supplied to use a different user than the one defined in +@code{configuration-user} global variable. @cindex time specification, procedure @cindex procedure time specification @@ -342,13 +344,12 @@ on Vixie syntax for this. @cindex job execution @cindex command execution @cindex execution -The second argument to the @code{(job)} function can be either a -string, a list, or a function. In all cases the command is executed in -the user's home directory, under the user's own UID. If a string is -passed, it is assumed to be shell script and is executed with the -user's default shell. If a list is passed it is assumed to be scheme -code and is eval'd as such. A supplied function should take exactly -zero arguments, and will be called at the pertinent times. +The second argument to the @code{(job)} function can be either a string, a +list, or a function. The command is executed in the home directory and with +the UID of @var{user}. If a string is passed, it is assumed to be shell +script and is executed with the user's default shell. If a list is passed it +is assumed to be scheme code and is eval'd as such. A supplied function +should take exactly zero arguments, and will be called at the pertinent times. @subsection Sending output as e-mail @cindex email output diff --git a/src/mcron/job-specifier.scm b/src/mcron/job-specifier.scm index 9e13551..6dacece 100644 --- a/src/mcron/job-specifier.scm +++ b/src/mcron/job-specifier.scm @@ -212,7 +212,8 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." ;; finding the next legitimate time from the current configuration time (set ;; right at the top of this program). -(define (job time-proc action . displayable) +(define* (job time-proc action #:optional displayable + #:key (user configuration-user)) (let ((action (cond ((procedure? action) action) ((list? action) (lambda () (primitive-eval action))) ((string? action) (lambda () (system action))) @@ -231,11 +232,14 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." "job: invalid first argument (next-time-function; " "should be function, string or list)")))) (displayable - (cond ((not (null? displayable)) (car displayable)) + (cond (displayable displayable) ((procedure? action) "Lambda function") ((string? action) action) ((list? action) (with-output-to-string - (lambda () (display action))))))) + (lambda () (display action)))))) + (user* (if (or (string? user) (integer? user)) + (getpw user) + user))) (add-job (lambda (current-time) (set! current-action-time current-time) ;; ?? !!!! Code @@ -251,4 +255,4 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." action displayable configuration-time - configuration-user))) + user*))) From 73b22946508d55bed9df1c050adeb289ff593540 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 5 Jul 2016 01:11:49 +0200 Subject: [PATCH 088/239] build: Install 'config.scm' file. * Makefile.am (mcronmodule_DATA): Add 'src/mcron/config.scm'. (CLEANFILES): Don't clean it. --- Makefile.am | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index e486db3..8c105e9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,6 +33,7 @@ modules = \ mcronmodule_DATA = \ $(modules:%.scm=%.go) \ + src/mcron/config.scm \ src/mcron/config.go dist_mcronmodule_DATA = \ @@ -103,8 +104,10 @@ uninstall-hook: fi EXTRA_DIST = BUGS -CLEANFILES = $(mcronmodule_DATA) DISTCLEANFILES = src/config.scm +CLEANFILES = \ + $(modules:%.scm=%.go) \ + src/mcron/config.go ## --------------- ## ## Documentation. ## From c87c643ca19b731ee6c53fbea72af8312ca6a725 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 9 May 2016 14:50:29 +0200 Subject: [PATCH 089/239] all: Separate programs in different executables. This improves readability and complies with the GNU Coding Standards by making the behavior of the programs independent of the name used to invoke them. * src/mcron/scripts/cron.scm: New file. * src/mcron/scripts/crontab.scm: Likewise. * src/mcron/scripts/mcron.scm: Likewise. * Makefile.am (dist_mcronmodule_DATA): Remove 'src/mcron/crontab.scm'. (bin_PROGRAMS): Add 'crontab'. (sbin_PROGRAMS): Add 'cron'. (mcron_CFLAGS, mcron_LDADD): Rename to ... (AM_CFLAGS, LDADD): ... these. (cron_SOURCES, cron_CPPFLAGS, cron_DEPENDENCIES) (crontab_SOURCES, crontab_CPPFLAGS, crontab_DEPENDENCIES) (mcron_CPPFLAGS, mcronscriptdir, dist_mcronscript_DATA): New variables. (modules): Redefine it in terms of other '_DATA' variables. * src/mcron/crontab.scm: Remove file. * src/mcron/main.scm (parse-args): New procedure. (command-name, command-type, options): Remove. (show-version): Adapt. (show-help, process-files-in-system-directory, cron-file-descriptors) (main, process-user-file, process-files-in-user-directory): Move procedures in the new files. * src/mcron.c (inner_main): Define the current module at compile time. * TODO: Update. * .gitignore: Likewise. --- .gitignore | 2 + Makefile.am | 41 +++-- TODO | 3 - src/mcron.c | 2 +- src/mcron/crontab.scm | 228 ------------------------ src/mcron/main.scm | 319 ++-------------------------------- src/mcron/scripts/cron.scm | 177 +++++++++++++++++++ src/mcron/scripts/crontab.scm | 225 ++++++++++++++++++++++++ src/mcron/scripts/mcron.scm | 136 +++++++++++++++ 9 files changed, 590 insertions(+), 543 deletions(-) delete mode 100644 src/mcron/crontab.scm create mode 100644 src/mcron/scripts/cron.scm create mode 100644 src/mcron/scripts/crontab.scm create mode 100644 src/mcron/scripts/mcron.scm diff --git a/.gitignore b/.gitignore index c064be1..d4fc72a 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ /build-aux/mdate-sh /build-aux/missing /build-aux/texinfo.tex +/cron +/crontab /doc/config.texi /doc/mcron.1 /doc/mcron.info diff --git a/Makefile.am b/Makefile.am index 8c105e9..dc47945 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,13 +16,25 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -bin_PROGRAMS = mcron -mcron_SOURCES = src/mcron.c -mcron_CFLAGS = @GUILE_CFLAGS@ -mcron_DEPENDENCIES = $(mcronmodule_DATA) -mcron_LDADD = @GUILE_LIBS@ +bin_PROGRAMS = mcron crontab +sbin_PROGRAMS = cron -modules = \ +AM_CFLAGS = @GUILE_CFLAGS@ +LDADD = @GUILE_LIBS@ + +mcron_SOURCES = src/mcron.c +mcron_CPPFLAGS = -DPROGRAM="\"mcron\"" +mcron_DEPENDENCIES = $(modules:%.scm=%.go) + +cron_SOURCES = src/mcron.c +cron_CPPFLAGS = -DPROGRAM="\"cron\"" +cron_DEPENDENCIES = $(modules:%.scm=%.go) + +crontab_SOURCES = src/mcron.c +crontab_CPPFLAGS = -DPROGRAM="\"crontab\"" +crontab_DEPENDENCIES = $(modules:%.scm=%.go) + +dist_mcronmodule_DATA = \ src/mcron/base.scm \ src/mcron/environment.scm \ src/mcron/job-specifier.scm \ @@ -32,13 +44,22 @@ modules = \ src/mcron/vixie-time.scm mcronmodule_DATA = \ - $(modules:%.scm=%.go) \ + $(dist_mcronmodule_DATA:%.scm=%.go) \ src/mcron/config.scm \ src/mcron/config.go -dist_mcronmodule_DATA = \ - $(modules) \ - src/mcron/crontab.scm +mcronscriptdir = $(mcronmoduledir)/scripts +dist_mcronscript_DATA = \ + src/mcron/scripts/cron.scm \ + src/mcron/scripts/crontab.scm \ + src/mcron/scripts/mcron.scm + +mcronscript_DATA = $(dist_mcronscript_DATA:%.scm=%.go) + +modules = \ + $(dist_mcronmodule_DATA) \ + $(dist_mcronscript_DATA) \ + src/mcron/config.scm # Unset 'GUILE_LOAD_COMPILED_PATH' altogether while compiling. Otherwise, if # $GUILE_LOAD_COMPILED_PATH contains $(mcronmoduledir), we may find .go files diff --git a/TODO b/TODO index b43f233..2b7329f 100644 --- a/TODO +++ b/TODO @@ -20,9 +20,6 @@ Maybe in the near future... core or other users' files up. Then allow scheme code in the system crontabs. - * Make mcron behavior not depend on the name used to invoke it, to conform - to GNU Coding Standards. - * Provide a test suite using SRFI-64 API. . diff --git a/src/mcron.c b/src/mcron.c index 92e1a37..026b077 100644 --- a/src/mcron.c +++ b/src/mcron.c @@ -53,7 +53,7 @@ inner_main (void *closure, int argc, char **argv) scm_c_eval_string ("(set! %load-compiled-path (cons \"" PACKAGE_LOAD_PATH "\" %load-compiled-path))"); } - scm_set_current_module (scm_c_resolve_module ("mcron main")); + scm_set_current_module (scm_c_resolve_module ("mcron scripts " PROGRAM)); /* Register set_cron_signals to be called from Guile. */ scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); scm_c_eval_string ("(main)"); diff --git a/src/mcron/crontab.scm b/src/mcron/crontab.scm deleted file mode 100644 index 6be5c61..0000000 --- a/src/mcron/crontab.scm +++ /dev/null @@ -1,228 +0,0 @@ -;; Copyright (C) 2003, 2014 Dale Mellor -;; -;; This file is part of GNU mcron. -;; -;; GNU mcron is free software: you can redistribute it and/or modify it under -;; the terms of the GNU General Public License as published by the Free -;; Software Foundation, either version 3 of the License, or (at your option) -;; any later version. -;; -;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT -;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -;; more details. -;; -;; You should have received a copy of the GNU General Public License along -;; with GNU mcron. If not, see . - - -;; Apart from the collecting of options and the handling of --help and --version -;; (which are done in the main.scm file), this file provides all the -;; functionality of the crontab personality. It is designed to be loaded and run -;; once, and then the calling program can exit and the crontab program will have -;; completed its function. - - - -;; Procedure to communicate with running cron daemon that a user has modified -;; his crontab. The user name is written to the /var/cron/socket UNIX socket. - -(let ((hit-server - (lambda (user-name) - (catch #t (lambda () - (let ((socket (socket AF_UNIX SOCK_STREAM 0))) - (connect socket AF_UNIX config-socket-file) - (display user-name socket) - (close socket))) - (lambda (key . args) - (display "Warning: a cron daemon is not running.\n"))))) - - - -;; Procedure to scan a file containing one user name per line (such as -;; /var/cron/allow and /var/cron/deny), and determine if the given name is in -;; there. The procedure returns #t, #f, or '() if the file does not exist. - - (in-access-file? - (lambda (file name) - (catch #t (lambda () - (with-input-from-file - file - (lambda () - (let loop ((input (read-line))) - (if (eof-object? input) - #f - (if (string=? input name) - #t - (loop (read-line)))))))) - (lambda (key . args) '())))) - - - - ;; This program should have been installed SUID root. Here we get the - ;; passwd entry for the real user who is running this program. - - (crontab-real-user (passwd:name (getpw (getuid))))) - - - - ;; If the real user is not allowed to use crontab due to the /var/cron/allow - ;; and/or /var/cron/deny files, bomb out now. - - (if (or (eq? (in-access-file? config-allow-file crontab-real-user) #f) - (eq? (in-access-file? config-deny-file crontab-real-user) #t)) - (mcron-error 6 "Access denied by system operator.")) - - - - ;; Check that no more than one of the mutually exclusive options are being - ;; used. - - (if (> (+ (if (option-ref options 'edit #f) 1 0) - (if (option-ref options 'list #f) 1 0) - (if (option-ref options 'remove #f) 1 0)) - 1) - (mcron-error 7 "Only one of options -e, -l or -r can be used.")) - - - - ;; Check that a non-root user is trying to read someone else's files. - - (if (and (not (eqv? (getuid) 0)) - (option-ref options 'user #f)) - (mcron-error 8 "Only root can use the -u option.")) - - - - (let ( - - - ;; Iff the --user option is given, the crontab-user may be different - ;; from the real user. - - (crontab-user (option-ref options 'user crontab-real-user)) - - - ;; So now we know which crontab file we will be manipulating. - - (crontab-file (string-append config-spool-dir "/" crontab-user)) - - - - ;; Display the prompt and wait for user to type his choice. Return #t if - ;; the answer begins with 'y' or 'Y', return #f if it begins with 'n' or - ;; 'N', otherwise ask again. - - (get-yes-no (lambda (prompt . re-prompt) - (if (not (null? re-prompt)) - (display "Please answer y or n.\n")) - (display (string-append prompt " ")) - (let ((r (read-line))) - (if (not (string-null? r)) - (case (string-ref r 0) - ((#\y #\Y) #t) - ((#\n #\N) #f) - (else (get-yes-no prompt #t))) - (get-yes-no prompt #t)))))) - - - - ;; There are four possible sub-personalities to the crontab personality: - ;; list, remove, edit and replace (when the user uses no options but - ;; supplies file names on the command line). - - (cond - - - ;; In the list personality, we simply open the crontab and copy it - ;; character-by-character to the standard output. If anything goes wrong, it - ;; can only mean that this user does not have a crontab file. - - ((option-ref options 'list #f) - (catch #t (lambda () - (with-input-from-file crontab-file (lambda () - (do ((input (read-char) (read-char))) - ((eof-object? input)) - (display input))))) - (lambda (key . args) - (display (string-append "No crontab for " - crontab-user - " exists.\n"))))) - - - ;; In the edit personality, we determine the name of a temporary file and an - ;; editor command, copy an existing crontab file (if it is there) to the - ;; temporary file, making sure the ownership is set so the real user can edit - ;; it; once the editor returns we try to read the file to check that it is - ;; parseable (but do nothing more with the configuration), and if it is okay - ;; (this program is still running!) we move the temporary file to the real - ;; crontab, wake the cron daemon up, and remove the temporary file. If the - ;; parse fails, we give user a choice of editing the file again or quitting - ;; the program and losing all changes made. - - ((option-ref options 'edit #f) - (let ((temp-file (string-append config-tmp-dir - "/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)) - (let retry () - (system (string-append - (or (getenv "VISUAL") (getenv "EDITOR") "vi") - " " - temp-file)) - (catch 'mcron-error - (lambda () (read-vixie-file temp-file)) - (lambda (key exit-code . msg) - (apply mcron-error 0 msg) - (if (get-yes-no "Edit again?") - (retry) - (begin - (mcron-error 0 "Crontab not changed") - (primitive-exit 0)))))) - (copy-file temp-file crontab-file) - (delete-file temp-file) - (hit-server crontab-user))) - - - ;; In the remove personality we simply make an effort to delete the crontab and - ;; wake the daemon. No worries if this fails. - - ((option-ref options 'remove #f) - (catch #t (lambda () (delete-file crontab-file) - (hit-server crontab-user)) - noop)) - - - ;; !!!! This comment is wrong. - - ;; In the case of the replace personality we loop over all the arguments on the - ;; command line, and for each one parse the file to make sure it is parseable - ;; (but subsequently ignore the configuration), and all being well we copy it - ;; to the crontab location; we deal with the standard input in the same way but - ;; different. :-) In either case the server is woken so that it will read the - ;; newly installed crontab. - - ((not (null? (option-ref options '() '()))) - (let ((input-file (car (option-ref options '() '())))) - (catch-mcron-error - (if (string=? input-file "-") - (let ((input-string (stdin->string))) - (read-vixie-port (open-input-string input-string)) - (with-output-to-file crontab-file (lambda () - (display input-string)))) - (begin - (read-vixie-file input-file) - (copy-file input-file crontab-file)))) - (hit-server crontab-user))) - - - ;; The user is being silly. The message here is identical to the one Vixie cron - ;; used to put out, for total compatibility. - - (else (mcron-error 15 - "usage error: file name must be specified for replace."))) - - -)) ;; End of file-level let-scopes. diff --git a/src/mcron/main.scm b/src/mcron/main.scm index db7dfd6..1faa1ae 100644 --- a/src/mcron/main.scm +++ b/src/mcron/main.scm @@ -16,30 +16,22 @@ ;; You should have received a copy of the GNU General Public License along ;; with GNU mcron. If not, see . -;;; This is the 'main' routine for the whole system; this module is the global -;;; entry point (after the minimal C wrapper); to all intents and purposes the -;;; program is pure Guile and starts here. - (define-module (mcron main) #:use-module (ice-9 getopt-long) #:use-module (ice-9 rdelim) - #:use-module (ice-9 regex) #:use-module (mcron config) #:use-module (mcron base) #:use-module (mcron job-specifier) #:use-module (mcron vixie-specification) - #:use-module (srfi srfi-2) - #:use-module (srfi srfi-26) - #:export (delete-run-file - main)) - -(define* (command-name #:optional (command (car (command-line)))) - "Extract the actual command name from COMMAND. This returns the last part -of COMMAND without any non-alphabetic characters. For example \"in.cron\" and -\"./mcron\" will return respectively \"cron\" and \"mcron\". - -When COMMAND is not specified this uses the first element of (command-line)." - (match:substring (regexp-exec (make-regexp "[[:alpha:]]*$") command))) + #:export (catch-mcron-error + mcron-error + parse-args + show-version + show-package-information + stdin->string + for-each-file + process-update-request) + #:re-export (option-ref)) (define (mcron-error exit-code . rest) "Print an error message (made up from the parts of REST), and if the @@ -47,7 +39,7 @@ EXIT-CODE error is fatal (present and non-zero) then exit to the system with EXIT-CODE." (with-output-to-port (current-error-port) (lambda () - (for-each display (append (list (command-name) ": ") rest)) + (for-each display (cons "mcron: " rest)) (newline))) (when (and exit-code (not (eq? exit-code 0))) (primitive-exit exit-code))) @@ -60,48 +52,14 @@ and exit with its error code." (lambda (key exit-code . msg) (apply mcron-error exit-code msg)))) -(define command-type - ;; We will be doing a lot of testing of the command name, so it makes sense - ;; to perform the string comparisons once and for all here. - (let* ((command (command-name)) - (command=? (cut string=? command <>))) - (cond ((command=? "mcron") 'mcron) - ((or (command=? "cron") (command=? "crond")) 'cron) - ((command=? "crontab") 'crontab) - (else (mcron-error 12 "The command name is invalid."))))) +(define (parse-args args option-desc-list) + "Parse ARGS with OPTION-DESC-LIST specification." + (catch 'misc-error + (lambda () (getopt-long args option-desc-list)) + (lambda (key func fmt args . rest) + (mcron-error 1 (apply format (append (list #f fmt) args)))))) -(define options - ;; There are a different set of options for the crontab personality compared - ;; to all the others, with the --help and --version options common to all - ;; the personalities. - (catch - 'misc-error - (lambda () - (getopt-long (command-line) - (append - (case command-type - ((crontab) - '((user (single-char #\u) (value #t)) - (edit (single-char #\e) (value #f)) - (list (single-char #\l) (value #f)) - (remove (single-char #\r) (value #f)))) - (else `((schedule (single-char #\s) (value #t) - (predicate - ,(lambda (value) - (string->number value)))) - (daemon (single-char #\d) (value #f)) - (noetc (single-char #\n) (value #f)) - (stdin (single-char #\i) (value #t) - (predicate - ,(lambda (value) - (or (string=? "vixie" value) - (string=? "guile" value)))))))) - '((version (single-char #\v) (value #f)) - (help (single-char #\h) (value #f)))))) - (lambda (key func fmt args . rest) - (mcron-error 1 (apply format (append (list #f fmt) args)))))) - -(define* (show-version #:optional (command (command-name))) +(define (show-version command) "Display version information for COMMAND and quit." (let* ((name config-package-name) (short-name (cadr (string-split name #\space))) @@ -111,8 +69,7 @@ Copyright (C) 2015 the ~a authors. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.\n" - command name version short-name) - (quit))) + command name version short-name))) (define (show-package-information) "Display where to get help and send bug reports." @@ -123,56 +80,6 @@ General help using GNU software: \n" config-package-name config-package-url)) -(define* (show-help #:optional (command (command-name))) - "Display informations of usage for COMMAND and quit." - (simple-format #t "Usage: ~a" command) - (display - (case command-type - ((mcron) - " [OPTIONS] [FILES] -Run an mcron process according to the specifications in the FILES (`-' for -standard input), or use all the files in ~/.config/cron (or the -deprecated ~/.cron) with .guile or .vixie extensions. - - -v, --version Display version - -h, --help Display this help message - -sN, --schedule[=]N Display the next N jobs that will be run by mcron - -d, --daemon Immediately detach the program from the terminal - and run as a daemon process - -i, --stdin=(guile|vixie) Format of data passed as standard input or - file arguments (default guile)") - ((cron) - " [OPTIONS] -Unless an option is specified, run a cron daemon as a detached process, -reading all the information in the users' crontabs and in /etc/crontab. - - -v, --version Display version - -h, --help Display this help message - -sN, --schedule[=]N Display the next N jobs that will be run by cron - -n, --noetc Do not check /etc/crontab for updates (HIGHLY - RECOMMENDED).") - ((crontab) - " [-u user] file - crontab [-u user] { -e | -l | -r } - (default operation is replace, per 1003.2) - -e (edit user's crontab) - -l (list user's crontab) - -r (delete user's crontab") - (else "\nrubbish"))) - (newline) - (show-package-information) - (quit)) - -(define (delete-run-file) - "Remove the /var/run/cron.pid file so that crontab and other invocations of -cron don't get the wrong idea that a daemon is currently running. This -procedure is called from the C front-end whenever a terminal signal is -received." - (catch #t (lambda () (delete-file config-pid-file) - (delete-file config-socket-file)) - noop) - (quit)) - (define (stdin->string) "Return standard input as a string." (with-output-to-string (lambda () (do ((in (read-char) (read-char))) @@ -188,83 +95,6 @@ is not specified" ((eof-object? file-name) (closedir dir)) (proc file-name)))) -(define process-user-file - (let ((guile-regexp (make-regexp "\\.gui(le)?$")) - (vixie-regexp (make-regexp "\\.vix(ie)?$"))) - (lambda* (file-name #:optional guile-syntax?) - "Process FILE-NAME according its extension. When GUILE-SYNTAX? is TRUE, -force guile syntax usage. If FILE-NAME format is not recognized, it is -silently ignored." - (cond ((string=? "-" file-name) - (if (string=? (option-ref options 'stdin "guile") "vixie") - (read-vixie-port (current-input-port)) - (eval-string (stdin->string)))) - ((or guile-syntax? (regexp-exec guile-regexp file-name)) - (load file-name)) - ((regexp-exec vixie-regexp file-name) - (read-vixie-file file-name)))))) - -(define (process-files-in-user-directory) - "Process files in $XDG_CONFIG_HOME/cron and/or ~/.cron directories (if -$XDG_CONFIG_HOME is not defined uses ~/.config/cron instead)." - (let ((errors 0) - (home-directory (passwd:dir (getpw (getuid))))) - (map (lambda (dir) - (catch #t - (lambda () - (for-each-file - (lambda (file) - (process-user-file (string-append dir "/" file))) - dir)) - (lambda (key . args) - (set! errors (1+ errors))))) - (list (string-append home-directory "/.cron") - (string-append (or (getenv "XDG_CONFIG_HOME") - (string-append home-directory "/.config")) - "/cron"))) - (when (eq? 2 errors) - (mcron-error 13 - "Cannot read files in your ~/.config/cron (or ~/.cron) directory.")))) - -(define (process-files-in-system-directory) - "Process all the files in the crontab directory. When the job procedure is -run on behalf of the configuration files, the jobs are registered on the -system with the appropriate user. Only root should be able to perform this -operation. The permissions on the /var/cron/tabs directory enforce this." - - (define (user-entry name) - ;; Return the user database entry if NAME is valid, otherwise #f. - (false-if-exception (getpwnam name))) - - (catch #t - (lambda () - (for-each-file - (lambda (user) - (and-let* ((entry (user-entry user))) ;crontab without user? - (set-configuration-user entry) - (catch-mcron-error - (read-vixie-file (string-append config-spool-dir "/" user))))) - config-spool-dir)) - (lambda (key . args) - (mcron-error 4 - "You do not have permission to access the system crontabs.")))) - -(define (cron-file-descriptors) - "Establish a socket to listen for updates from a crontab program, and return -a list containing the file descriptors correponding to the files read by -crontab. This requires that command-type is 'cron." - (if (eq? command-type 'cron) - (catch #t - (lambda () - (let ((sock (socket AF_UNIX SOCK_STREAM 0))) - (bind sock AF_UNIX config-socket-file) - (listen sock 5) - (list sock))) - (lambda (key . args) - (delete-file config-pid-file) - (mcron-error 1 "Cannot bind to UNIX socket " config-socket-file))) - '())) - (define (process-update-request fdes-list) "Read a user name from the socket, dealing with the /etc/crontab special case, remove all the user's jobs from the job list, and then re-read the @@ -286,116 +116,3 @@ comes in on the above socket." (remove-user-jobs user) (set-configuration-user user) (read-vixie-file (string-append config-spool-dir "/" user-name))))))) - - -;;; -;;; Entry point. -;;; - -(define (main . args) - ;; Turn debugging on if indicated. - (when config-debug - (debug-enable 'backtrace)) - (when (option-ref options 'version #f) - (show-version)) - (when (option-ref options 'help #f) - (show-help)) - - ;; 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. - ;; - ;; Otherwise, clear the MAILTO environment variable so that output from cron - ;; jobs is sent to the various users (this may still be overridden in the - ;; configuration files), and call the function in the C wrapper to set up - ;; terminal signal responses to vector to the procedure above. The PID file - ;; will be filled in properly later when we have forked our daemon process - ;; (but not done if we are only viewing the schedules). - (when (eq? command-type 'cron) - (unless (eqv? (getuid) 0) - (mcron-error 16 - "This program must be run by the root user (and should have been " - "installed as such).")) - (when (access? config-pid-file F_OK) - (mcron-error 1 - "A cron daemon is already running.\n (If you are sure this is not" - " true, remove the file\n " config-pid-file ".)")) - (unless (option-ref options 'schedule #f) - (with-output-to-file config-pid-file noop)) - (setenv "MAILTO" #f) - ;; XXX: At compile time, this yields a "possibly unbound variable" - ;; warning, but this is OK since it is bound in the C wrapper. - (c-set-cron-signals)) - - ;; Now we have the procedures in place for dealing with the contents of - ;; configuration files, the crontab personality is able to validate such - ;; files. If the user requested the crontab personality, we load and run the - ;; code here and then get out. - (when (eq? command-type 'crontab) - (load "crontab.scm") - (quit)) - - ;; 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 passed on the command line, or else all the ones in the user's - ;; .config/cron (or .cron) directory. If we are running under the cron - ;; personality, we read the /var/cron/tabs directory and also the - ;; /etc/crontab file. - (case command-type - ((mcron) - (if (null? (option-ref options '() '())) - (process-files-in-user-directory) - (for-each (lambda (file-path) (process-user-file file-path #t)) - (option-ref options '() '())))) - ((cron) - (process-files-in-system-directory) - (use-system-job-list) - (catch-mcron-error (read-vixie-file "/etc/crontab" - parse-system-vixie-line)) - (use-user-job-list) - (unless (option-ref options 'noetc #f) - (display "\ -WARNING: cron will check for updates to /etc/crontab EVERY MINUTE. If you do -not use this file, or you are prepared to manually restart cron whenever you -make a change, then it is HIGHLY RECOMMENDED that you use the --noetc -option.\n") - (set-configuration-user "root") - (job '(- (next-minute-from (next-minute)) 6) - check-system-crontab - "/etc/crontab update checker.")))) - - ;; If the user has requested a schedule of jobs that will run, we provide - ;; the information here and then get out. Start by determining the number - ;; of time points in the future that output is required for. This may be - ;; provided on the command line as a parameter to the --schedule option, or - ;; else we assume a default of 8. Finally, ensure that the count is some - ;; positive integer. - (and-let* ((count (option-ref options 'schedule #f))) - (set! count (string->number count)) - (display (get-schedule (if (<= count 0) 1 count))) - (quit)) - - ;; If we are supposed to run as a daemon process (either a --daemon option - ;; has been explicitly used, or we are running as cron or crond), detach - ;; from the terminal now. If we are running as cron, we can now write the - ;; PID file. - (when (option-ref options 'daemon (eq? command-type 'cron)) - (unless (eqv? (primitive-fork) 0) - (quit)) - (setsid) - (when (eq? command-type 'cron) - (with-output-to-file config-pid-file - (lambda () (display (getpid)) (newline))))) - - ;; Now the main loop. Forever execute the run-job-loop procedure in the - ;; mcron base, and when it drops out (can only be because a message has come - ;; in on the socket) we process the socket request before restarting the - ;; loop again. Sergey Poznyakoff: we can also drop out of run-job-loop - ;; because of a SIGCHLD, so must test FDES-LIST. - (catch-mcron-error - (let ((fdes-list (cron-file-descriptors))) - (while #t - (run-job-loop fdes-list) - (unless (null? fdes-list) - (process-update-request fdes-list)))))) diff --git a/src/mcron/scripts/cron.scm b/src/mcron/scripts/cron.scm new file mode 100644 index 0000000..dd8f5ad --- /dev/null +++ b/src/mcron/scripts/cron.scm @@ -0,0 +1,177 @@ +;;;; cron -- daemon for running jobs at scheduled times +;;; Copyright © 2003, 2012 Dale Mellor +;;; Copyright © 2015, 2016 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . + +(define-module (mcron scripts cron) + #:use-module (mcron base) + #:use-module (mcron config) + #:use-module (mcron job-specifier) + #:use-module (mcron main) + #:use-module (mcron vixie-specification) + #:use-module (srfi srfi-2) + #:export (main)) + +(define (show-help) + (display "Usage: cron [OPTIONS] +Unless an option is specified, run a cron daemon as a detached process, +reading all the information in the users' crontabs and in /etc/crontab. + + -v, --version Display version + -h, --help Display this help message + -sN, --schedule[=]N Display the next N jobs that will be run by cron + -n, --noetc Do not check /etc/crontab for updates (HIGHLY + RECOMMENDED).") + (newline) + (show-package-information)) + +(define %options + `((schedule (single-char #\s) (value #t) + (predicate ,(λ (str) (string->number str)))) + (noetc (single-char #\n) (value #f)) + (version (single-char #\v) (value #f)) + (help (single-char #\h) (value #f)))) + +(define (delete-run-file) + "Remove the /var/run/cron.pid file so that crontab and other invocations of +cron don't get the wrong idea that a daemon is currently running. This +procedure is called from the C front-end whenever a terminal signal is +received." + (catch #t + (λ () + (delete-file config-pid-file) + (delete-file config-socket-file)) + noop) + (quit)) + +(define (cron-file-descriptors) + "Establish a socket to listen for updates from a crontab program, and return +a list containing the file descriptors correponding to the files read by +crontab. This requires that command-type is 'cron." + (catch #t + (λ () + (let ((sock (socket AF_UNIX SOCK_STREAM 0))) + (bind sock AF_UNIX config-socket-file) + (listen sock 5) + (list sock))) + (λ (key . args) + (delete-file config-pid-file) + (mcron-error 1 "Cannot bind to UNIX socket " config-socket-file)))) + +(define (process-files-in-system-directory) + "Process all the files in the crontab directory. When the job procedure is +run on behalf of the configuration files, the jobs are registered on the +system with the appropriate user. Only root should be able to perform this +operation. The permissions on the /var/cron/tabs directory enforce this." + + (define (user-entry name) + ;; Return the user database entry if NAME is valid, otherwise #f. + (false-if-exception (getpwnam name))) + + (catch #t + (λ () + (for-each-file + (λ (user) + (and-let* ((entry (user-entry user))) ;crontab without user? + (set-configuration-user entry) + (catch-mcron-error + (read-vixie-file (string-append config-spool-dir "/" user))))) + config-spool-dir)) + (λ (key . args) + (mcron-error 4 + "You do not have permission to access the system crontabs.")))) + +(define (%process-files schedule? noetc?) + ;; XXX: What is this supposed to do? + (when schedule? + (with-output-to-file config-pid-file noop)) + ;; Clear MAILTO so that outputs are sent to the various users. + (setenv "MAILTO" #f) + ;; XXX: At compile time, this yields a "possibly unbound variable" warning, + ;; but this is OK since it is bound in the C wrapper. + (c-set-cron-signals) + ;; 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 passed on the command line, or else all the ones in the user's + ;; .config/cron (or .cron) directory. If we are running under the cron + ;; personality, we read the /var/cron/tabs directory and also the + ;; /etc/crontab file. + (process-files-in-system-directory) + (use-system-job-list) + (catch-mcron-error + (read-vixie-file "/etc/crontab" parse-system-vixie-line)) + (use-user-job-list) + (unless noetc? + (display "\ +WARNING: cron will check for updates to /etc/crontab EVERY MINUTE. If you do +not use this file, or you are prepared to manually restart cron whenever you +make a change, then it is HIGHLY RECOMMENDED that you use the --noetc +option.\n") + (set-configuration-user "root") + (job '(- (next-minute-from (next-minute)) 6) + check-system-crontab + "/etc/crontab update checker."))) + + +;;; +;;; Entry point. +;;; + +(define* (main #:optional (args (command-line))) + (let ((opts (parse-args args %options))) + (when config-debug + (debug-enable 'backtrace)) + (cond + ((option-ref opts 'help #f) + (show-help) + (exit 0)) + ((option-ref opts 'version #f) + (show-version "cron") + (exit 0)) + ((not (zero? (getuid))) + (mcron-error 16 + "This program must be run by the root user (and should" + " have been installed as such).")) + ((access? config-pid-file F_OK) + (mcron-error 1 + "A cron daemon is already running.\n (If you are sure" + " this is not true, remove the file\n " + config-pid-file ".)")) + (else + (%process-files (option-ref opts 'schedule #f) + (option-ref opts 'noetc #f)) + (cond ((option-ref opts 'schedule #f) ;display jobs schedule + => (λ (count) + (display (get-schedule (max 1 (string->number count)))) + (exit 0))) + (else (case (primitive-fork) ;run the daemon + ((0) + (setsid) + ;; we can now write the PID file. + (with-output-to-file config-pid-file + (λ () (display (getpid)) (newline)))) + (else (exit 0))))) + ;; Forever execute the 'run-job-loop', and when it drops out (can + ;; only be because a message has come in on the socket) we + ;; process the socket request before restarting the loop again. + (catch-mcron-error + (let ((fdes-list (cron-file-descriptors))) + (while #t + (run-job-loop fdes-list) + (unless (null? fdes-list) + (process-update-request fdes-list))))))))) diff --git a/src/mcron/scripts/crontab.scm b/src/mcron/scripts/crontab.scm new file mode 100644 index 0000000..43ae8f6 --- /dev/null +++ b/src/mcron/scripts/crontab.scm @@ -0,0 +1,225 @@ +;;;; crontab -- edit user's cron tabs +;;; Copyright © 2003, 2004 Dale Mellor +;;; Copyright © 2016 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . + +(define-module (mcron scripts crontab) + #:use-module (ice-9 rdelim) + #:use-module (mcron config) + #:use-module (mcron main) + #:use-module (mcron vixie-specification) + #:export (main)) + +(define* (show-help) + (display "Usage: crontab [-u user] file + crontab [-u user] { -e | -l | -r } + (default operation is replace, per 1003.2) + -e (edit user's crontab) + -l (list user's crontab) + -r (delete user's crontab") + (newline) + (show-package-information)) + +(define %options + '((user (single-char #\u) (value #t)) + (edit (single-char #\e) (value #f)) + (list (single-char #\l) (value #f)) + (remove (single-char #\r) (value #f)) + (version (single-char #\v) (value #f)) + (help (single-char #\h) (value #f)))) + + +;;; +;;; Entry point. +;;; + +(define* (main #:optional (args (command-line))) + (let ((opts (parse-args args %options))) + (when config-debug + (debug-enable 'backtrace)) + (cond ((option-ref opts 'help #f) + (show-help) + (exit 0)) + ((option-ref opts 'version #f) + (show-version "crontab") + (exit 0))) + (let ((hit-server + (λ (user-name) + ;; Procedure to communicate with running cron daemon that a user + ;; has modified his crontab. The user name is written to the + ;; /var/cron/socket UNIX socket. + (catch #t + (λ () + (let ((socket (socket AF_UNIX SOCK_STREAM 0))) + (connect socket AF_UNIX config-socket-file) + (display user-name socket) + (close socket))) + (λ (key . args) + (display "Warning: a cron daemon is not running.\n"))))) + + ;; Procedure to scan a file containing one user name per line (such + ;; as /var/cron/allow and /var/cron/deny), and determine if the + ;; given name is in there. The procedure returns #t, #f, or '() if + ;; the file does not exist. + (in-access-file? + (λ (file name) + (catch #t + (λ () + (with-input-from-file file + (λ () + (let loop ((input (read-line))) + (if (eof-object? input) + #f + (if (string=? input name) + #t + (loop (read-line)))))))) + (λ (key . args) '())))) + + ;; This program should have been installed SUID root. Here we get + ;; the passwd entry for the real user who is running this program. + (crontab-real-user (passwd:name (getpw (getuid))))) + + ;; If the real user is not allowed to use crontab due to the + ;; /var/cron/allow and/or /var/cron/deny files, bomb out now. + (if (or (eq? (in-access-file? config-allow-file crontab-real-user) #f) + (eq? (in-access-file? config-deny-file crontab-real-user) #t)) + (mcron-error 6 "Access denied by system operator.")) + + ;; Check that no more than one of the mutually exclusive options are + ;; being used. + (when (> (+ (if (option-ref opts 'edit #f) 1 0) + (if (option-ref opts 'list #f) 1 0) + (if (option-ref opts 'remove #f) 1 0)) + 1) + (mcron-error 7 "Only one of options -e, -l or -r can be used.")) + + ;; Check that a non-root user is trying to read someone else's files. + (when (and (not (zero? (getuid))) + (option-ref opts 'user #f)) + (mcron-error 8 "Only root can use the -u option.")) + + (letrec* (;; Iff the --user option is given, the crontab-user may be + ;; different from the real user. + (crontab-user (option-ref opts 'user crontab-real-user)) + ;; So now we know which crontab file we will be manipulating. + (crontab-file (string-append config-spool-dir "/" crontab-user)) + ;; Display the prompt and wait for user to type his + ;; choice. Return #t if the answer begins with 'y' or 'Y', + ;; return #f if it begins with 'n' or 'N', otherwise ask + ;; again. + (get-yes-no (λ (prompt . re-prompt) + (if (not (null? re-prompt)) + (display "Please answer y or n.\n")) + (display (string-append prompt " ")) + (let ((r (read-line))) + (if (not (string-null? r)) + (case (string-ref r 0) + ((#\y #\Y) #t) + ((#\n #\N) #f) + (else (get-yes-no prompt #t))) + (get-yes-no prompt #t)))))) + ;; There are four possible sub-personalities to the crontab + ;; personality: list, remove, edit and replace (when the user uses no + ;; options but supplies file names on the command line). + (cond + ;; In the list personality, we simply open the crontab and copy it + ;; character-by-character to the standard output. If anything goes + ;; wrong, it can only mean that this user does not have a crontab + ;; file. + ((option-ref opts 'list #f) + (catch #t + (λ () + (with-input-from-file crontab-file + (λ () + (do ((input (read-char) (read-char))) + ((eof-object? input)) + (display input))))) + (λ (key . args) + (display (string-append "No crontab for " + crontab-user + " exists.\n"))))) + + ;; In the edit personality, we determine the name of a temporary file + ;; and an editor command, copy an existing crontab file (if it is + ;; there) to the temporary file, making sure the ownership is set so + ;; the real user can edit it; once the editor returns we try to read + ;; the file to check that it is parseable (but do nothing more with + ;; the configuration), and if it is okay (this program is still + ;; running!) we move the temporary file to the real crontab, wake the + ;; cron daemon up, and remove the temporary file. If the parse fails, + ;; we give user a choice of editing the file again or quitting the + ;; program and losing all changes made. + ((option-ref opts 'edit #f) + (let ((temp-file (string-append config-tmp-dir + "/crontab." + (number->string (getpid))))) + (catch #t + (λ () (copy-file crontab-file temp-file)) + (λ (key . args) (with-output-to-file temp-file noop))) + (chown temp-file (getuid) (getgid)) + (let retry () + (system (string-append + (or (getenv "VISUAL") (getenv "EDITOR") "vi") + " " + temp-file)) + (catch 'mcron-error + (λ () (read-vixie-file temp-file)) + (λ (key exit-code . msg) + (apply mcron-error 0 msg) + (if (get-yes-no "Edit again?") + (retry) + (begin + (mcron-error 0 "Crontab not changed") + (primitive-exit 0)))))) + (copy-file temp-file crontab-file) + (delete-file temp-file) + (hit-server crontab-user))) + + ;; In the remove personality we simply make an effort to delete the + ;; crontab and wake the daemon. No worries if this fails. + ((option-ref opts 'remove #f) + (catch #t + (λ () + (delete-file crontab-file) + (hit-server crontab-user)) + noop)) + + ;; XXX: This comment is wrong. + ;; In the case of the replace personality we loop over all the + ;; arguments on the command line, and for each one parse the file to + ;; make sure it is parseable (but subsequently ignore the + ;; configuration), and all being well we copy it to the crontab + ;; location; we deal with the standard input in the same way but + ;; different. :-) In either case the server is woken so that it will + ;; read the newly installed crontab. + ((not (null? (option-ref opts '() '()))) + (let ((input-file (car (option-ref opts '() '())))) + (catch-mcron-error + (if (string=? input-file "-") + (let ((input-string (stdin->string))) + (read-vixie-port (open-input-string input-string)) + (with-output-to-file crontab-file + (λ () (display input-string)))) + (begin + (read-vixie-file input-file) + (copy-file input-file crontab-file)))) + (hit-server crontab-user))) + + ;; The user is being silly. The message here is identical to the one + ;; Vixie cron used to put out, for total compatibility. + (else (mcron-error 15 + "usage error: file name must be specified for replace."))))))) diff --git a/src/mcron/scripts/mcron.scm b/src/mcron/scripts/mcron.scm new file mode 100644 index 0000000..30b2d2a --- /dev/null +++ b/src/mcron/scripts/mcron.scm @@ -0,0 +1,136 @@ +;;;; mcron -- run jobs at scheduled times +;;; Copyright © 2003, 2012 Dale Mellor +;;; Copyright © 2015, 2016 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . + +(define-module (mcron scripts mcron) + #:use-module (mcron base) + #:use-module (mcron config) + #:use-module (mcron job-specifier) ;for user/system files + #:use-module (mcron main) + #:use-module (mcron vixie-specification) + #:export (main)) + +(define (show-help) + (display "Usage: mcron [OPTIONS] [FILES] +Run an mcron process according to the specifications in the FILES (`-' for +standard input), or use all the files in ~/.config/cron (or the +deprecated ~/.cron) with .guile or .vixie extensions. + + -v, --version Display version + -h, --help Display this help message + -sN, --schedule[=]N Display the next N jobs that will be run by mcron + -d, --daemon Immediately detach the program from the terminal + and run as a daemon process + -i, --stdin=(guile|vixie) Format of data passed as standard input or + file arguments (default guile)") + (newline) + (show-package-information)) + +(define %options + `((schedule (single-char #\s) (value #t) + (predicate ,(λ (str) (string->number str)))) + (daemon (single-char #\d) (value #f)) + (noetc (single-char #\n) (value #f)) + (stdin (single-char #\i) (value #t) + (predicate ,(λ (val) + (or (string=? val "guile") + (string=? val "vixie"))))) + (version (single-char #\v) (value #f)) + (help (single-char #\h) (value #f)))) + +(define process-user-file + (let ((guile-regexp (make-regexp "\\.gui(le)?$")) + (vixie-regexp (make-regexp "\\.vix(ie)?$"))) + (lambda* (file-name #:optional guile-syntax? #:key (input "guile")) + "Process FILE-NAME according its extension. When GUILE-SYNTAX? is TRUE, +force guile syntax usage. If FILE-NAME format is not recognized, it is +silently ignored." + (cond ((string=? "-" file-name) + (if (string=? input "vixie") + (read-vixie-port (current-input-port)) + (eval-string (stdin->string)))) + ((or guile-syntax? (regexp-exec guile-regexp file-name)) + (load file-name)) + ((regexp-exec vixie-regexp file-name) + (read-vixie-file file-name)))))) + +(define (process-files-in-user-directory input-type) + "Process files in $XDG_CONFIG_HOME/cron and/or ~/.cron directories (if +$XDG_CONFIG_HOME is not defined uses ~/.config/cron instead)." + (let ((errors 0) + (home-directory (passwd:dir (getpw (getuid))))) + (map (λ (dir) + (catch #t + (λ () + (for-each-file + (λ (file) + (process-user-file (string-append dir "/" file) + #:input input-type)) + dir)) + (λ (key . args) + (set! errors (1+ errors))))) + (list (string-append home-directory "/.cron") + (string-append (or (getenv "XDG_CONFIG_HOME") + (string-append home-directory "/.config")) + "/cron"))) + (when (eq? 2 errors) + (mcron-error 13 + "Cannot read files in your ~/.config/cron (or ~/.cron) directory.")))) + +(define (%process-files files input-type) + (if (null? files) + (process-files-in-user-directory input-type) + (for-each (λ (file) (process-user-file file #t)) files))) + + +;;; +;;; Entry point. +;;; + +(define* (main #:optional (args (command-line))) + (let ((opts (parse-args args %options))) + (when config-debug + (debug-enable 'backtrace)) + (cond ((option-ref opts 'help #f) + (show-help) + (exit 0)) + ((option-ref opts 'version #f) + (show-version "mcron") + (exit 0)) + (else + (%process-files (option-ref opts '() '()) + (option-ref opts 'stdin "guile")) + (cond ((option-ref opts 'schedule #f) ;display jobs schedule + => (λ (count) + (display (get-schedule (max 1 (string->number count)))) + (exit 0))) + ((option-ref opts 'daemon #f) ;run mcron as a daemon + (case (primitive-fork) + ((0) (setsid)) + (else (exit 0))))) + ;; Forever execute the 'run-job-loop', and when it drops out (can + ;; only be because a message has come in on the socket) we process + ;; the socket request before restarting the loop again. + (catch-mcron-error + (let ((fdes-list '())) + (while #t + (run-job-loop fdes-list) + ;; we can also drop out of run-job-loop because of a SIGCHLD, + ;; so must test FDES-LIST. + (unless (null? fdes-list) + (process-update-request fdes-list))))))))) From c9064dde98b2a91be6c9f23c37168c7468fd873f Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 9 May 2016 23:59:26 +0200 Subject: [PATCH 090/239] build: Fix prerequisite for mcron man page. * Makefile.am (doc/mcron.1): Depend on the Guile script instead of the C wrapper. --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index dc47945..ec98ef3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -145,7 +145,7 @@ TEXI2DVI = texi2dvi -I doc # Not part of formal package building, but a rule for manual use to get the # elemental man page. Will only work once the mcron program is installed. -doc/mcron.1: src/mcron.c +doc/mcron.1: src/mcron/scripts/mcron.scm -$(AM_V_HELP2MAN)$(MKDIR_P) `dirname "$@"` ; \ $(top_builddir)/pre-inst-env $(HELP2MAN) \ -n 'a program to run tasks at regular (or not) intervals' \ From 9d173e23bc0bf39c1114f2ac6fc6e5c1e56dd55f Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 10 May 2016 01:06:10 +0200 Subject: [PATCH 091/239] job-specifier: range: Add tests. * build-aux/test-driver.scm: New script. * configure.ac (AC_REQUIRE_AUX_FILE): Add it. * tests/job-specifier.scm: New test. * Makefile.am (TEST_EXTENSIONS, AM_TESTS_ENVIRONMENT, SCM_LOG_DRIVER) (TESTS): New variables. (EXTRA_DIST): Update. * .gitignore: Likewise. --- .gitignore | 2 + Makefile.am | 11 ++- build-aux/test-driver.scm | 193 ++++++++++++++++++++++++++++++++++++++ configure.ac | 1 + tests/job-specifier.scm | 43 +++++++++ 5 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 build-aux/test-driver.scm create mode 100644 tests/job-specifier.scm diff --git a/.gitignore b/.gitignore index d4fc72a..b998b13 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ *.go +*.log *.o +*.trs *~ .deps .dirstamp diff --git a/Makefile.am b/Makefile.am index ec98ef3..020aac6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -61,6 +61,15 @@ modules = \ $(dist_mcronscript_DATA) \ src/mcron/config.scm +TEST_EXTENSIONS = .scm +AM_TESTS_ENVIRONMENT = env GUILE_AUTO_COMPILE='0' + +SCM_LOG_DRIVER = \ + $(builddir)/pre-inst-env $(GUILE) \ + $(srcdir)/build-aux/test-driver.scm + +TESTS = tests/job-specifier.scm + # Unset 'GUILE_LOAD_COMPILED_PATH' altogether while compiling. Otherwise, if # $GUILE_LOAD_COMPILED_PATH contains $(mcronmoduledir), we may find .go files # in there that are newer than the local .scm files (for instance because the @@ -124,7 +133,7 @@ uninstall-hook: rm -f $(fpp){cron,crontab}$(EXEEXT); \ fi -EXTRA_DIST = BUGS +EXTRA_DIST = BUGS $(TESTS) DISTCLEANFILES = src/config.scm CLEANFILES = \ $(modules:%.scm=%.go) \ diff --git a/build-aux/test-driver.scm b/build-aux/test-driver.scm new file mode 100644 index 0000000..01edf93 --- /dev/null +++ b/build-aux/test-driver.scm @@ -0,0 +1,193 @@ +;;;; test-driver.scm - Guile test driver for Automake testsuite harness + +(define script-version "2016-05-09.22") ;UTC + +;;; Copyright (C) 2015, 2016 Mathieu Lirzin +;;; +;;; This program is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; This program is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with this program. If not, see . +;;; +;;; As a special exception to the GNU General Public License, if you +;;; distribute this file as part of a program that contains a configuration +;;; script generated by Autoconf, you may include it under the same +;;; distribution terms that you use for the rest of that program. + +;;;; Commentary: +;;; +;;; This script provides a Guile test driver using the SRFI-64 Scheme API for +;;; test suites. SRFI-64 is distributed with Guile since version 2.0.9. +;;; +;;;; Code: + +(use-modules (ice-9 getopt-long) + (ice-9 pretty-print) + (srfi srfi-26) + (srfi srfi-64)) + +(define (show-help) + (display "Usage: + test-driver --test-name=NAME --log-file=PATH --trs-file=PATH + [--expect-failure={yes|no}] [--color-tests={yes|no}] + [--enable-hard-errors={yes|no}] [--brief={yes|no}}] [--] + TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS] +The '--test-name', '--log-file' and '--trs-file' options are mandatory.\n")) + +(define %options + '((test-name (value #t)) + (log-file (value #t)) + (trs-file (value #t)) + (color-tests (value #t)) + (expect-failure (value #t)) ;XXX: not implemented yet + (enable-hard-errors (value #t)) ;not implemented in SRFI-64 + (brief (value #t)) + (help (single-char #\h) (value #f)) + (version (single-char #\V) (value #f)))) + +(define (option->boolean options key) + "Return #t if the value associated with KEY in OPTIONS is \"yes\"." + (and=> (option-ref options key #f) (cut string=? <> "yes"))) + +(define* (test-display field value #:optional (port (current-output-port)) + #:key pretty?) + "Display \"FIELD: VALUE\\n\" on PORT." + (if pretty? + (begin + (format port "~A:~%" field) + (pretty-print value port #:per-line-prefix "+ ")) + (format port "~A: ~A~%" field value))) + +(define* (result->string symbol #:key colorize?) + "Return SYMBOL as an upper case string. Use colors when COLORIZE is #t." + (let ((result (string-upcase (symbol->string symbol)))) + (if colorize? + (string-append (case symbol + ((pass) "") ;green + ((xfail) "") ;light green + ((skip) "") ;blue + ((fail xpass) "") ;red + ((error) "")) ;magenta + result + "") ;no color + result))) + +(define* (test-runner-gnu test-name #:key color? brief? out-port trs-port) + "Return an custom SRFI-64 test runner. TEST-NAME is a string specifying the +file name of the current the test. COLOR? specifies whether to use colors, +and BRIEF?, well, you know. OUT-PORT and TRS-PORT must be output ports. The +current output port is supposed to be redirected to a '.log' file." + + (define (test-on-test-begin-gnu runner) + ;; Procedure called at the start of an individual test case, before the + ;; test expression (and expected value) are evaluated. + (let ((result (cute assq-ref (test-result-alist runner) <>))) + (test-display "test-name" (result 'test-name)) + (test-display "location" + (string-append (result 'source-file) ":" + (number->string (result 'source-line)))) + (test-display "source" (result 'source-form) #:pretty? #t))) + + (define (test-on-test-end-gnu runner) + ;; Procedure called at the end of an individual test case, when the result + ;; of the test is available. + (let* ((results (test-result-alist runner)) + (result? (cut assq <> results)) + (result (cut assq-ref results <>))) + (unless brief? + ;; Display the result of each test case on the console. + (test-display + (result->string (test-result-kind runner) #:colorize? color?) + (string-append test-name " - " (test-runner-test-name runner)) + out-port)) + (when (result? 'expected-value) + (test-display "expected-value" (result 'expected-value))) + (when (result? 'expected-error) + (test-display "expected-error" (result 'expected-error) #:pretty? #t)) + (when (result? 'actual-value) + (test-display "actual-value" (result 'actual-value))) + (when (result? 'actual-error) + (test-display "actual-error" (result 'actual-error) #:pretty? #t)) + (test-display "result" (result->string (result 'result-kind))) + (newline) + (test-display ":test-result" + (string-append (result->string (test-result-kind runner)) + " " (test-runner-test-name runner)) + trs-port))) + + (define (test-on-group-end-gnu runner) + ;; Procedure called by a 'test-end', including at the end of a test-group. + (let ((fail (or (positive? (test-runner-fail-count runner)) + (positive? (test-runner-xpass-count runner)))) + (skip (or (positive? (test-runner-skip-count runner)) + (positive? (test-runner-xfail-count runner))))) + ;; XXX: The global results need some refinements for XPASS. + (test-display ":global-test-result" + (if fail "FAIL" (if skip "SKIP" "PASS")) + trs-port) + (test-display ":recheck" + (if fail "yes" "no") + trs-port) + (test-display ":copy-in-global-log" + (if (or fail skip) "yes" "no") + trs-port) + (when brief? + ;; Display the global test group result on the console. + (test-display (result->string (if fail 'fail (if skip 'skip 'pass)) + #:colorize? color?) + test-name + out-port)) + #f)) + + (let ((runner (test-runner-null))) + (test-runner-on-test-begin! runner test-on-test-begin-gnu) + (test-runner-on-test-end! runner test-on-test-end-gnu) + (test-runner-on-group-end! runner test-on-group-end-gnu) + (test-runner-on-bad-end-name! runner test-on-bad-end-name-simple) + runner)) + + +;;; +;;; Entry point. +;;; + +(let* ((opts (getopt-long (command-line) %options)) + (option (cut option-ref opts <> <>))) + (cond + ((option 'help #f) (show-help)) + ((option 'version #f) (format #t "test-driver.scm ~A~%" script-version)) + (else + (let ((log (open-file (option 'log-file "") "w0")) + (trs (open-file (option 'trs-file "") "wl")) + (out (duplicate-port (current-output-port) "wl"))) + (redirect-port log (current-output-port)) + (redirect-port log (current-warning-port)) + (redirect-port log (current-error-port)) + (test-with-runner + (test-runner-gnu (option 'test-name #f) + #:color? (option->boolean opts 'color-tests) + #:brief? (option->boolean opts 'brief) + #:out-port out #:trs-port trs) + (load (string-append (getcwd) "/" (car (option '() '("")))))) + (close-port log) + (close-port trs) + (close-port out)))) + (exit 0)) + +;;; Local Variables: +;;; eval: (add-hook 'write-file-functions 'time-stamp) +;;; time-stamp-start: "(define script-version \"" +;;; time-stamp-format: "%:y-%02m-%02d.%02H" +;;; time-stamp-time-zone: "UTC" +;;; time-stamp-end: "\") ;UTC" +;;; End: + +;;;; test-driver.scm ends here. diff --git a/configure.ac b/configure.ac index c6c77d9..892eb19 100644 --- a/configure.ac +++ b/configure.ac @@ -26,6 +26,7 @@ AC_INIT([GNU Mcron], [1.0.8], [bug-mcron@gnu.org]) AC_CONFIG_HEADER([src/config.h]) AC_CONFIG_SRCDIR([src/mcron.c]) AC_CONFIG_AUX_DIR([build-aux]) +AC_REQUIRE_AUX_FILE([test-driver.scm]) AM_INIT_AUTOMAKE([subdir-objects]) AM_SILENT_RULES([yes]) # enables silent rules by default diff --git a/tests/job-specifier.scm b/tests/job-specifier.scm new file mode 100644 index 0000000..889530b --- /dev/null +++ b/tests/job-specifier.scm @@ -0,0 +1,43 @@ +;;;; job-specifier.scm -- tests for (mcron job-specifier) module +;;; Copyright © 2016 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . + +(use-modules (srfi srfi-64) + (mcron job-specifier)) + +(test-begin "job-specifier") + +(test-equal "range: basic" + '(0 1 2 3 4 5 6 7 8 9) + (range 0 10)) + +(test-equal "range: positive step" + '(0 2 4 6 8) + (range 0 10 2)) + +(test-assert "range: zero step" + ;; Since this behavior is undefined, only check if range doesn't crash. + (range 0 5 0)) + +(test-assert "range: negative step" + ;; Since this behavior is undefined, only check if range doesn't crash. + (range 0 5 -2)) + +(test-assert "range: reverse boundaries" + (range 10 3)) + +(test-end) From e9fde01d27e25847efb5e9bec9f9dfd9fd8478bf Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 10 May 2016 02:22:09 +0200 Subject: [PATCH 092/239] environment: modify-environment: Add tests. * tests/environment.scm: New test. * Makefile.am (TESTS): Add it. --- Makefile.am | 4 +++- tests/environment.scm | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tests/environment.scm diff --git a/Makefile.am b/Makefile.am index 020aac6..c878685 100644 --- a/Makefile.am +++ b/Makefile.am @@ -68,7 +68,9 @@ SCM_LOG_DRIVER = \ $(builddir)/pre-inst-env $(GUILE) \ $(srcdir)/build-aux/test-driver.scm -TESTS = tests/job-specifier.scm +TESTS = \ + tests/environment.scm \ + tests/job-specifier.scm # Unset 'GUILE_LOAD_COMPILED_PATH' altogether while compiling. Otherwise, if # $GUILE_LOAD_COMPILED_PATH contains $(mcronmoduledir), we may find .go files diff --git a/tests/environment.scm b/tests/environment.scm new file mode 100644 index 0000000..1bc34a6 --- /dev/null +++ b/tests/environment.scm @@ -0,0 +1,39 @@ +;;;; environment.scm -- tests for (mcron environment) module +;;; Copyright © 2016 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . + +(use-modules (srfi srfi-64) + (mcron environment)) + +(test-begin "environment") + +(test-assert "modifiy-environment: basic" + (begin + (modify-environment '(("FOO" . "bar")) (getpw)) + (equal? (getenv "FOO") "bar"))) + +(test-assert "modifiy-environment: user & logname" + ;; Check that USER and LOGNAME environment variables can't be changed. + (let* ((user-entry (pk (getpw))) + (user-name (passwd:name user-entry))) + (modify-environment '(("USER" . "alice")) user-entry) + (modify-environment '(("LOGNAME" . "bob")) user-entry) + (equal? user-name + (pk (getenv "USER")) + (pk (getenv "LOGNAME"))))) + +(test-end) From 4a56db16097b06a9e894d5bb0d3997fe8cf0c1eb Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 10 May 2016 20:46:06 +0200 Subject: [PATCH 093/239] doc: Generate a man page for every program. * Makefile.am (dist_man_MANS): Add 'cron' and 'crontab' man page. Generate man pages in $(srcdir). (MAINTAINERCLEANFILES, gen_man): New variables. (AM_V_HELP2MAN, AM_V_HELP2MAN_, AM_V_HELP2MAN_0): Delete unneeded variables. ($(srcdir)/doc/crontab.1, $(srcdir)/doc/cron.8): New targets. (doc/mcron.1): Rename to ... ($(srcdir)/doc/mcron.1)): ... this. --- .gitignore | 2 ++ Makefile.am | 37 +++++++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index b998b13..cc8e31d 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,8 @@ /cron /crontab /doc/config.texi +/doc/cron.8 +/doc/crontab.1 /doc/mcron.1 /doc/mcron.info /doc/stamp-vti diff --git a/Makefile.am b/Makefile.am index c878685..305421d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -136,6 +136,7 @@ uninstall-hook: fi EXTRA_DIST = BUGS $(TESTS) +MAINTAINERCLEANFILES = $(dist_man_MANS) DISTCLEANFILES = src/config.scm CLEANFILES = \ $(modules:%.scm=%.go) \ @@ -148,19 +149,35 @@ CLEANFILES = \ info_TEXINFOS = doc/mcron.texi doc_mcron_TEXINFOS = doc/fdl.texi nodist_doc_mcron_TEXINFOS = doc/config.texi -dist_man_MANS = doc/mcron.1 +dist_man_MANS = \ + $(srcdir)/doc/mcron.1 \ + $(srcdir)/doc/crontab.1 \ + $(srcdir)/doc/cron.8 # XXX: Allow the inclusion of 'doc/fdl.texi' and 'doc/config.texi' inside # 'doc/mcron.texi' for 'dvi' and 'pdf' targets. TEXI2DVI = texi2dvi -I doc -# Not part of formal package building, but a rule for manual use to get the -# elemental man page. Will only work once the mcron program is installed. -doc/mcron.1: src/mcron/scripts/mcron.scm - -$(AM_V_HELP2MAN)$(MKDIR_P) `dirname "$@"` ; \ - $(top_builddir)/pre-inst-env $(HELP2MAN) \ - -n 'a program to run tasks at regular (or not) intervals' \ - ./mcron > $@ +# The 'case' ensures the man pages are only generated if the corresponding +# source script (the first prerequisite) has been changed. The second +# prerequisites is solely meant to force these docs to be made only after +# executables have been compiled. +gen_man = \ + case '$?' in \ + *$<*) $(AM_V_P) && set -x || echo " HELP2MAN $@"; \ + LANGUAGE= $(top_builddir)/pre-inst-env $(HELP2MAN) \ + -s $$man_section -S GNU -p $(PACKAGE_TARNAME) -o $@ $$prog;; \ + *) : ;; \ + esac + +$(srcdir)/doc/mcron.1: src/mcron/scripts/mcron.scm mcron + -@prog="mcron"; man_section=1; $(gen_man) + +$(srcdir)/doc/crontab.1: src/mcron/scripts/crontab.scm crontab + -@prog="crontab"; man_section=1; $(gen_man) + +$(srcdir)/doc/cron.8: src/mcron/scripts/cron.scm cron + -@prog="cron"; man_section=8; $(gen_man) ## -------------- ## ## Silent rules. ## @@ -169,7 +186,3 @@ doc/mcron.1: src/mcron/scripts/mcron.scm AM_V_GUILEC = $(AM_V_GUILEC_$(V)) AM_V_GUILEC_ = $(AM_V_GUILEC_$(AM_DEFAULT_VERBOSITY)) AM_V_GUILEC_0 = @echo " GUILEC " $@; - -AM_V_HELP2MAN = $(AM_V_HELP2MAN_$(V)) -AM_V_HELP2MAN_ = $(AM_V_HELP2MAN_$(AM_DEFAULT_VERBOSITY)) -AM_V_HELP2MAN_0 = @echo " HELP2MAN" $@; From 10c9f31c6c6dee962e114a0ea494088d8fdb3502 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 10 May 2016 21:00:59 +0200 Subject: [PATCH 094/239] build: Use Automake warnings. * configure.ac (AM_INIT_AUTOMAKE): Add more warnings. * Makefile.am (AM_V_GUILEC, AM_V_GUILEC_, AM_V_GUILEC_0): Rename to ... (guilec_verbose, guilec_verbose_, guilec_verbose_0): ... these. Make them more portable. This follows an example from Automake manual. --- Makefile.am | 8 ++++---- configure.ac | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile.am b/Makefile.am index 305421d..0504a2c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -83,7 +83,7 @@ TESTS = \ # XXX: Use the C locale for when Guile lacks # . .scm.go: - $(AM_V_GUILEC)$(MKDIR_P) `dirname "$@"` ; \ + $(guilec_verbose)$(MKDIR_P) `dirname "$@"` ; \ export GUILE_AUTO_COMPILE=0 ; unset GUILE_LOAD_COMPILED_PATH ; \ LC_ALL=C \ $(top_builddir)/pre-inst-env $(GUILD) compile \ @@ -183,6 +183,6 @@ $(srcdir)/doc/cron.8: src/mcron/scripts/cron.scm cron ## Silent rules. ## ## -------------- ## -AM_V_GUILEC = $(AM_V_GUILEC_$(V)) -AM_V_GUILEC_ = $(AM_V_GUILEC_$(AM_DEFAULT_VERBOSITY)) -AM_V_GUILEC_0 = @echo " GUILEC " $@; +guilec_verbose = $(guilec_verbose_@AM_V@) +guilec_verbose_ = $(guilec_verbose_@AM_DEFAULT_V@) +guilec_verbose_0 = @echo " GUILEC " $@; diff --git a/configure.ac b/configure.ac index 892eb19..da860f9 100644 --- a/configure.ac +++ b/configure.ac @@ -27,7 +27,7 @@ AC_CONFIG_HEADER([src/config.h]) AC_CONFIG_SRCDIR([src/mcron.c]) AC_CONFIG_AUX_DIR([build-aux]) AC_REQUIRE_AUX_FILE([test-driver.scm]) -AM_INIT_AUTOMAKE([subdir-objects]) +AM_INIT_AUTOMAKE([subdir-objects -Wall -Wno-override]) AM_SILENT_RULES([yes]) # enables silent rules by default moduledir="${datarootdir}/guile/site/2.0" From 6a82b53ddd8cb93f60121cb02e1276e089926ad1 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 5 Jul 2016 01:56:57 +0200 Subject: [PATCH 095/239] build: Silence 'guild compile' output. * Makefile.am (devnull_verbose, devnull_verbose_, devnull_verbose_0): New variables (.scm.go): Use $(devnull_verbose). --- Makefile.am | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 0504a2c..ddb1c26 100644 --- a/Makefile.am +++ b/Makefile.am @@ -90,7 +90,7 @@ TESTS = \ --load-path="$(top_builddir)/src" \ --load-path="$(top_srcdir)/src" \ --warn=format --warn=unbound-variable --warn=arity-mismatch \ - --target="$(host)" --output="$@" "$<" + --target="$(host)" --output="$@" "$<" $(devnull_verbose) SUFFIXES = .go noinst_SCRIPTS = pre-inst-env @@ -186,3 +186,7 @@ $(srcdir)/doc/cron.8: src/mcron/scripts/cron.scm cron guilec_verbose = $(guilec_verbose_@AM_V@) guilec_verbose_ = $(guilec_verbose_@AM_DEFAULT_V@) guilec_verbose_0 = @echo " GUILEC " $@; + +devnull_verbose = $(devnull_verbose_@AM_V@) +devnull_verbose_ = $(devnull_verbose_@AM_DEFAULT_V@) +devnull_verbose_0 = >/dev/null From 245413041c1ddee4bb7d752f6f1044750b887df8 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 17 Jul 2016 00:10:35 +0200 Subject: [PATCH 096/239] build: Define PACKAGE_LOAD_PATH in Makefile. Previously PACKAGE_LOAD_PATH was set in config header which wasn't correctly expanded due to the presence of ${prefix} in ${moduledir}. Let 'make' handle the expansion. * Makefile.am (AM_CPPFLAGS): New variable. (cron_CPPFLAGS, crontab_CPPFLAGS, mcron_CPPFLAGS): Use it. * configure.ac (PACKAGE_LOAD_PATH): Undefine it. (AC_CONFIG_HEADER): Remove macro. * src/mcron.c: Adapt to it. --- Makefile.am | 7 ++++--- configure.ac | 4 +--- src/mcron.c | 1 - 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Makefile.am b/Makefile.am index ddb1c26..d01e730 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,19 +19,20 @@ bin_PROGRAMS = mcron crontab sbin_PROGRAMS = cron +AM_CPPFLAGS = -DPACKAGE_LOAD_PATH=\"$(moduledir)\" AM_CFLAGS = @GUILE_CFLAGS@ LDADD = @GUILE_LIBS@ mcron_SOURCES = src/mcron.c -mcron_CPPFLAGS = -DPROGRAM="\"mcron\"" +mcron_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"mcron\"" mcron_DEPENDENCIES = $(modules:%.scm=%.go) cron_SOURCES = src/mcron.c -cron_CPPFLAGS = -DPROGRAM="\"cron\"" +cron_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"cron\"" cron_DEPENDENCIES = $(modules:%.scm=%.go) crontab_SOURCES = src/mcron.c -crontab_CPPFLAGS = -DPROGRAM="\"crontab\"" +crontab_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"crontab\"" crontab_DEPENDENCIES = $(modules:%.scm=%.go) dist_mcronmodule_DATA = \ diff --git a/configure.ac b/configure.ac index da860f9..5ec29aa 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,6 @@ AC_PREREQ(2.61) AC_INIT([GNU Mcron], [1.0.8], [bug-mcron@gnu.org]) -AC_CONFIG_HEADER([src/config.h]) AC_CONFIG_SRCDIR([src/mcron.c]) AC_CONFIG_AUX_DIR([build-aux]) AC_REQUIRE_AUX_FILE([test-driver.scm]) @@ -31,9 +30,8 @@ AM_INIT_AUTOMAKE([subdir-objects -Wall -Wno-override]) AM_SILENT_RULES([yes]) # enables silent rules by default moduledir="${datarootdir}/guile/site/2.0" +AC_SUBST([moduledir]) AC_SUBST([mcronmoduledir], ["${moduledir}/mcron"]) -AC_DEFINE_UNQUOTED([PACKAGE_LOAD_PATH], ["${moduledir}"], - [Define to the guile modules location of this package.]) AC_MSG_CHECKING([whether debugging is requested]) AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], diff --git a/src/mcron.c b/src/mcron.c index 026b077..a52c073 100644 --- a/src/mcron.c +++ b/src/mcron.c @@ -22,7 +22,6 @@ is needed because the crontab personality requires SUID which is not permitted for executable scripts. */ -#include "config.h" #include #include #include From ae6deb8ea23570c02a7b575a53bba37048aab59f Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 17 Jul 2016 19:18:29 +0200 Subject: [PATCH 097/239] job-specifier: Use 'inf' thunk. * src/mcron/job-specifier.scm (%find-best-next): Call 'inf' thunk instead of defining an arbitrary high integer. (bump-time): Adapt to it. --- src/mcron/job-specifier.scm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mcron/job-specifier.scm b/src/mcron/job-specifier.scm index 6dacece..5b17984 100644 --- a/src/mcron/job-specifier.scm +++ b/src/mcron/job-specifier.scm @@ -50,11 +50,11 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." (unfold (cut >= <> end) identity (cute + <> (max step 1)) start)) (define (%find-best-next current next-list) - ;; Takes a value and a list of possible next values (all assumed less than - ;; 9999). It returns a pair consisting of the smallest element of the - ;; NEXT-LIST, and the smallest element larger than the CURRENT value. If an - ;; example of the latter cannot be found, 9999 will be returned. - (let loop ((smallest 9999) (closest+ 9999) (lst next-list)) + ;; Takes a value and a list of possible next values. It returns a pair + ;; consisting of the smallest element of the NEXT-LIST, and the smallest + ;; element larger than the CURRENT value. If an example of the latter + ;; cannot be found, +INF.0 will be returned. + (let loop ((smallest (inf)) (closest+ (inf)) (lst next-list)) (match lst (() (cons smallest closest+)) ((time . rest) @@ -83,7 +83,7 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." (if (null? value-list) (set-component! time (+ (component time) 1)) (let ((best-next (%find-best-next (component time) (car value-list)))) - (if (eqv? 9999 (cdr best-next)) + (if (inf? (cdr best-next)) (begin (set-higher-component! time (+ (higher-component time) 1)) (set-component! time (car best-next))) From ea2058f14a67bb2169255c61fd9751169c43b433 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 18 Jul 2016 00:31:23 +0200 Subject: [PATCH 098/239] job-specifier: Rewrite 'bump-time'. * src/mcron/job-specifier.scm (bump-time): Use 'match'. --- src/mcron/job-specifier.scm | 55 ++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/mcron/job-specifier.scm b/src/mcron/job-specifier.scm index 5b17984..e66621e 100644 --- a/src/mcron/job-specifier.scm +++ b/src/mcron/job-specifier.scm @@ -62,36 +62,35 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." (if (> time current) (min time closest+) closest+) rest))))) -;; Internal function to return the time corresponding to some near future -;; hour. If hour-list is not supplied, the time returned corresponds to the -;; start of the next hour of the day. -;; -;; If the hour-list is supplied the time returned corresponds to the first hour -;; of the day in the future which is contained in the list. If all the values in -;; the list are less than the current hour, then the time returned will -;; correspond to the first hour in the list *on the following day*. -;; -;; ... except that the function is actually generalized to deal with seconds, -;; minutes, etc., in an obvious way :-) -;; -;; Note that value-list always comes from an optional argument to a procedure, -;; so is wrapped up as the first element of a list (i.e. it is a list inside a -;; list). - (define (bump-time time value-list component higher-component set-component! set-higher-component!) - (if (null? value-list) - (set-component! time (+ (component time) 1)) - (let ((best-next (%find-best-next (component time) (car value-list)))) - (if (inf? (cdr best-next)) - (begin - (set-higher-component! time (+ (higher-component time) 1)) - (set-component! time (car best-next))) - (set-component! time (cdr best-next))))) - (car (mktime time))) - - - + ;; Return the time corresponding to some near future hour. If hour-list is + ;; not supplied, the time returned corresponds to the start of the next hour + ;; of the day. + ;; + ;; If the hour-list is supplied the time returned corresponds to the first + ;; hour of the day in the future which is contained in the list. If all the + ;; values in the list are less than the current hour, then the time returned + ;; will correspond to the first hour in the list *on the following day*. + ;; + ;; ... except that the function is actually generalized to deal with + ;; seconds, minutes, etc., in an obvious way :-) + ;; + ;; Note that value-list always comes from an optional argument to a + ;; procedure, so is wrapped up as the first element of a list (i.e. it is a + ;; list inside a list). + (match value-list + (() + (set-component! time (1+ (component time)))) + ((val . rest) + (match (%find-best-next (component time) val) + ((smallest . closest+) + (cond ((inf? closest+) + (set-higher-component! time (1+ (higher-component time))) + (set-component! time smallest)) + (else + (set-component! time closest+))))))) + (first (mktime time))) ;; Set of configuration methods which use the above general function to bump ;; specific components of time to the next legitimate value. In each case, all From 109555a9ddf5a60e5e0530b64105127bcaa27c91 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 18 Jul 2016 01:25:21 +0200 Subject: [PATCH 099/239] job-specifier: Add %current-action-time parameter object. * src/mcron/job-specifier.scm (current-action-time): Rename to ... (%current-action-time): ... this. Make it a parameter object. (job, maybe-args): Adapt. --- src/mcron/job-specifier.scm | 47 +++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/src/mcron/job-specifier.scm b/src/mcron/job-specifier.scm index e66621e..bf1ec89 100644 --- a/src/mcron/job-specifier.scm +++ b/src/mcron/job-specifier.scm @@ -137,17 +137,13 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." (let ((time (localtime current-time))) (bump-time time second-list tm:sec tm:min set-tm:sec set-tm:min))) - - -;; The current-action-time is the time a job was last run, the time from which -;; the next time to run a job must be computed. (When the program is first run, -;; this time is set to the configuration time so that jobs run from that moment -;; forwards.) Once we have this, we supply versions of the time computation -;; commands above which implicitly assume this value. - -(define current-action-time 0) - - +(define %current-action-time + ;; The time a job was last run, the time from which the next time to run a + ;; job must be computed. (When the program is first run, this time is set to + ;; the configuration time so that jobs run from that moment forwards.) Once + ;; we have this, we supply versions of the time computation commands above + ;; which implicitly assume this value. + (make-parameter 0)) ;; We want to provide functions which take a single optional argument (as well ;; as implicitly the current action time), but unlike usual scheme behaviour if @@ -157,14 +153,14 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." (define (maybe-args function args) (if (null? args) - (function current-action-time) - (function current-action-time (car args)))) + (function (%current-action-time)) + (function (%current-action-time) (car args)))) ;; These are the convenience functions we were striving to define for the ;; configuration files. They are wrappers for the next-X-from functions above, -;; but implicitly use the current-action-time for the time argument. +;; but implicitly use %CURRENT-ACTION-TIME for the time argument. (define (next-year . args) (maybe-args next-year-from args)) (define (next-month . args) (maybe-args next-month-from args)) @@ -204,7 +200,7 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." ;; string this is parsed as a Vixie-style time specification, and if it is a ;; list then we arrange to eval it (but note that such lists are expected to ;; ignore the function parameter - the last run time is always read from the -;; current-action-time global variable). A similar normalization is applied to +;; %CURRENT-ACTION-TIME parameter object). A similar normalization is applied to ;; the action. ;; ;; Here we also compute the first time that the job is supposed to run, by @@ -240,17 +236,16 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." (getpw user) user))) (add-job (lambda (current-time) - (set! current-action-time current-time) ;; ?? !!!! Code - - ;; Contributed by Sergey Poznyakoff to allow for daylight savings - ;; time changes. - (let* ((next (time-proc current-time)) - (gmtoff (tm:gmtoff (localtime next))) - (d (+ next (- gmtoff - (tm:gmtoff (localtime current-time)))))) - (if (eqv? (tm:gmtoff (localtime d)) gmtoff) - d - next))) + (parameterize ((%current-action-time current-time)) + ;; Allow for daylight savings time changes. + (let* ((next (time-proc current-time)) + (gmtoff (tm:gmtoff (localtime next))) + (d (+ next + (- gmtoff + (tm:gmtoff (localtime current-time)))))) + (if (eqv? (tm:gmtoff (localtime d)) gmtoff) + d + next)))) action displayable configuration-time From 913e3c65e4f56476e8ac69f4892cf92c125751ec Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 18 Jul 2016 13:31:34 +0200 Subject: [PATCH 100/239] job-specifier: Use #:optional keyword argument. * src/mcron/job-specifier.scm (next-year, next-year-from, next-month) (next-month-from, next-day, next-day-from, next-hour, next-hour-from) (next-minute, next-minute-from, next-second, next-second-from): Use #:optional keyword argument. (maybe-args): Remove unneeded procedure. --- src/mcron/job-specifier.scm | 54 +++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/mcron/job-specifier.scm b/src/mcron/job-specifier.scm index bf1ec89..5d60484 100644 --- a/src/mcron/job-specifier.scm +++ b/src/mcron/job-specifier.scm @@ -98,7 +98,7 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." ;; example the time of the next year will be the time at which the next year ;; actually starts. -(define (next-year-from current-time . year-list) +(define* (next-year-from current-time #:optional (year-list '())) (let ((time (localtime current-time))) (set-tm:mon time 0) (set-tm:mday time 1) @@ -107,7 +107,7 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." (set-tm:sec time 0) (bump-time time year-list tm:year tm:year set-tm:year set-tm:year))) -(define (next-month-from current-time . month-list) +(define* (next-month-from current-time #:optional (month-list '())) (let ((time (localtime current-time))) (set-tm:mday time 1) (set-tm:hour time 0) @@ -115,28 +115,32 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." (set-tm:sec time 0) (bump-time time month-list tm:mon tm:year set-tm:mon set-tm:year))) -(define (next-day-from current-time . day-list) +(define* (next-day-from current-time #:optional (day-list '())) (let ((time (localtime current-time))) (set-tm:hour time 0) (set-tm:min time 0) (set-tm:sec time 0) (bump-time time day-list tm:mday tm:mon set-tm:mday set-tm:mon))) -(define (next-hour-from current-time . hour-list) +(define* (next-hour-from current-time #:optional (hour-list '())) (let ((time (localtime current-time))) (set-tm:min time 0) (set-tm:sec time 0) (bump-time time hour-list tm:hour tm:mday set-tm:hour set-tm:mday))) -(define (next-minute-from current-time . minute-list) +(define* (next-minute-from current-time #:optional (minute-list '())) (let ((time (localtime current-time))) (set-tm:sec time 0) (bump-time time minute-list tm:min tm:hour set-tm:min set-tm:hour))) -(define (next-second-from current-time . second-list) +(define* (next-second-from current-time #:optional (second-list '())) (let ((time (localtime current-time))) (bump-time time second-list tm:sec tm:min set-tm:sec set-tm:min))) +;;; The following procedures are convenient for configuration files. They are +;;; wrappers for the next-X-from functions above, by implicitly using +;;; %CURRENT-ACTION-TIME as the time argument. + (define %current-action-time ;; The time a job was last run, the time from which the next time to run a ;; job must be computed. (When the program is first run, this time is set to @@ -145,31 +149,29 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." ;; which implicitly assume this value. (make-parameter 0)) -;; We want to provide functions which take a single optional argument (as well -;; as implicitly the current action time), but unlike usual scheme behaviour if -;; the argument is missing we want to act like it is really missing, and if it -;; is there we want to act like it is a genuine argument, not a list of -;; optionals. +(define* (next-year #:optional (args '())) + "Compute the next year from %CURRENT-ACTION-TIME parameter object." + (next-year-from (%current-action-time) args)) -(define (maybe-args function args) - (if (null? args) - (function (%current-action-time)) - (function (%current-action-time) (car args)))) +(define* (next-month #:optional (args '())) + "Compute the next month from %CURRENT-ACTION-TIME parameter object." + (next-month-from (%current-action-time) args)) +(define* (next-day #:optional (args '())) + "Compute the next day from %CURRENT-ACTION-TIME parameter object." + (next-day-from (%current-action-time) args)) +(define* (next-hour #:optional (args '())) + "Compute the next hour from %CURRENT-ACTION-TIME parameter object." + (next-hour-from (%current-action-time) args)) -;; These are the convenience functions we were striving to define for the -;; configuration files. They are wrappers for the next-X-from functions above, -;; but implicitly use %CURRENT-ACTION-TIME for the time argument. - -(define (next-year . args) (maybe-args next-year-from args)) -(define (next-month . args) (maybe-args next-month-from args)) -(define (next-day . args) (maybe-args next-day-from args)) -(define (next-hour . args) (maybe-args next-hour-from args)) -(define (next-minute . args) (maybe-args next-minute-from args)) -(define (next-second . args) (maybe-args next-second-from args)) - +(define* (next-minute #:optional (args '())) + "Compute the next minute from %CURRENT-ACTION-TIME parameter object." + (next-minute-from (%current-action-time) args)) +(define* (next-second #:optional (args '())) + "Compute the next second from %CURRENT-ACTION-TIME parameter object." + (next-second-from (%current-action-time) args)) ;; The default user for running jobs is the current one (who invoked this ;; program). There are exceptions: when cron parses /etc/crontab the user is From 74babba80ef6c2084035e1bc5d78d31021341cb6 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 18 Jul 2016 14:32:52 +0200 Subject: [PATCH 101/239] base: Rewrite 'run-job-loop'. * src/mcron/base.scm (run-job-loop): Use #:optional keyword argument, and 'match'. --- src/mcron/base.scm | 77 ++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 44 deletions(-) diff --git a/src/mcron/base.scm b/src/mcron/base.scm index aae5fe5..b779c8a 100644 --- a/src/mcron/base.scm +++ b/src/mcron/base.scm @@ -20,6 +20,7 @@ (define-module (mcron base) + #:use-module (ice-9 match) #:use-module (mcron environment) #:use-module (srfi srfi-9) #:export (add-job @@ -225,50 +226,38 @@ (eqv? (car (waitpid WAIT_ANY WNOHANG)) 0))) (set! number-children (- number-children 1)))) - - -;; Now the main loop. 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 and reap any children (old jobs) that have -;; completed. Repeat ad infinitum. -;; -;; Note that, if we wake ahead of time, it can only mean that a signal has been -;; sent by a crontab job to tell us to re-read a crontab file. In this case we -;; break out of the loop here, and let the main procedure deal with the -;; situation (it will eventually re-call this function, thus maintaining the -;; loop). - -(define (run-job-loop . fd-list) - +(define* (run-job-loop #:optional fd-list) + ;; 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 and reap any children (old jobs) that have completed. Repeat ad + ;; infinitum. + ;; + ;; Note that, if we wake ahead of time, it can only mean that a signal has + ;; been sent by a crontab job to tell us to re-read a crontab file. In this + ;; case we break out of the loop here, and let the main procedure deal with + ;; the situation (it will eventually re-call this function, thus maintaining + ;; the loop). (call-with-current-continuation (lambda (break) - - (let ((fd-list (if (null? fd-list) '() (car fd-list)))) - - (let loop () - - (let* ((next-jobs (find-next-jobs)) - (next-time (car next-jobs)) - (next-jobs-list (cdr next-jobs)) - (sleep-time (if next-time (- next-time (current-time)) - 2000000000))) - - (and (> sleep-time 0) - (if (not (null? - (catch 'system-error - (lambda () + (let loop () + (match (find-next-jobs) + ((next-time . next-jobs-lst) + (let ((sleep-time (if next-time + (- next-time (current-time)) + 2000000000))) + (when (and + (> sleep-time 0) + (not (null? (catch 'system-error + (λ () (car (select fd-list '() '() sleep-time))) - (lambda (key . args) ;; Exception add by Sergey - ;; Poznyakoff. - (if (member (car (last args)) - (list EINTR EAGAIN)) - (begin - (child-cleanup) '()) - (apply throw key args)))))) - (break))) - - (run-jobs next-jobs-list) - - (child-cleanup) - - (loop))))))) + (λ (key . args) + (let ((err (car (last args)))) + (cond ((member err (list EINTR EAGAIN)) + (child-cleanup) + '()) + (else + (apply throw key args))))))))) + (break)) + (run-jobs next-jobs-lst) + (child-cleanup) + (loop)))))))) From 19d68f7dd67dea1e5e11d5014766157d45e5ebf4 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 18 Jul 2016 16:30:11 +0200 Subject: [PATCH 102/239] build: Rename 'mcron.c' to 'wrapper.c'. * src/mcron.c: Rename to ... * src/wrapper.c: ... this. * Makefile.am (mcron_SOURCES, cron_SOURCES, crontab_SOURCES): Adapt to it. * configure.ac (AC_CONFIG_SRCDIR): Likewise. --- Makefile.am | 6 +++--- configure.ac | 2 +- src/{mcron.c => wrapper.c} | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) rename src/{mcron.c => wrapper.c} (98%) diff --git a/Makefile.am b/Makefile.am index d01e730..61f1c7b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,15 +23,15 @@ AM_CPPFLAGS = -DPACKAGE_LOAD_PATH=\"$(moduledir)\" AM_CFLAGS = @GUILE_CFLAGS@ LDADD = @GUILE_LIBS@ -mcron_SOURCES = src/mcron.c +mcron_SOURCES = src/wrapper.c mcron_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"mcron\"" mcron_DEPENDENCIES = $(modules:%.scm=%.go) -cron_SOURCES = src/mcron.c +cron_SOURCES = src/wrapper.c cron_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"cron\"" cron_DEPENDENCIES = $(modules:%.scm=%.go) -crontab_SOURCES = src/mcron.c +crontab_SOURCES = src/wrapper.c crontab_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"crontab\"" crontab_DEPENDENCIES = $(modules:%.scm=%.go) diff --git a/configure.ac b/configure.ac index 5ec29aa..5b2fcf6 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ AC_PREREQ(2.61) AC_INIT([GNU Mcron], [1.0.8], [bug-mcron@gnu.org]) -AC_CONFIG_SRCDIR([src/mcron.c]) +AC_CONFIG_SRCDIR([src/wrapper.c]) AC_CONFIG_AUX_DIR([build-aux]) AC_REQUIRE_AUX_FILE([test-driver.scm]) AM_INIT_AUTOMAKE([subdir-objects -Wall -Wno-override]) diff --git a/src/mcron.c b/src/wrapper.c similarity index 98% rename from src/mcron.c rename to src/wrapper.c index a52c073..a5b46db 100644 --- a/src/mcron.c +++ b/src/wrapper.c @@ -1,7 +1,6 @@ -/* mcron - run jobs at scheduled times - - Copyright (C) 2015, 2016 Mathieu Lirzin +/* wrapper.c -- C code booting Guile Copyright (C) 2003, 2014 Dale Mellor + Copyright (C) 2015, 2016 Mathieu Lirzin This file is part of GNU Mcron. From 2cdd544a56e4b340f1744cfe2ab6439aa815045c Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 18 Jul 2016 17:25:27 +0200 Subject: [PATCH 103/239] maint: Reformat copyright notices and copying permission statements. --- Makefile.am | 13 ++++--- configure.ac | 41 ++++++++++---------- src/mcron/base.scm | 39 ++++++++++--------- src/mcron/config.scm.in | 40 +++++++++----------- src/mcron/environment.scm | 62 +++++++++++++++---------------- src/mcron/job-specifier.scm | 50 +++++++++++++------------ src/mcron/main.scm | 35 ++++++++--------- src/mcron/redirect.scm | 61 +++++++++++++++--------------- src/mcron/vixie-specification.scm | 49 ++++++++++++------------ src/mcron/vixie-time.scm | 33 ++++++++-------- src/wrapper.c | 4 +- 11 files changed, 215 insertions(+), 212 deletions(-) diff --git a/Makefile.am b/Makefile.am index 61f1c7b..52a8499 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,20 +1,21 @@ ## Process this file with automake to produce Makefile.in. - -# Copyright (C) 2003 Dale Mellor -# Copyright (C) 2015, 2016 Mathieu Lirzin +# Copyright © 2003 Dale Mellor +# Copyright © 2015, 2016 Mathieu Lirzin # -# This program is free software: you can redistribute it and/or modify +# This file is part of GNU Mcron. +# +# GNU Mcron is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # -# This program is distributed in the hope that it will be useful, +# GNU Mcron is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# along with GNU Mcron. If not, see . bin_PROGRAMS = mcron crontab sbin_PROGRAMS = cron diff --git a/configure.ac b/configure.ac index 5b2fcf6..97c900b 100644 --- a/configure.ac +++ b/configure.ac @@ -1,25 +1,22 @@ -# -*- Autoconf -*- -# Process this file with autoconf to produce a configure script. - - -# Copyright (C) 2003, 2005, 2012, 2014 Dale Mellor -# Copyright (C) 2015, 2016 Mathieu Lirzin -# -# This file is part of GNU mcron. -# -# GNU mcron is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free -# Software Foundation, either version 3 of the License, or (at your option) -# any later version. -# -# GNU mcron is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along -# with GNU mcron. If not, see . - +## Process this file with autoconf to produce a configure script. +# Copyright © 2003, 2005, 2012, 2014 Dale Mellor +# +# Copyright © 2015, 2016 Mathieu Lirzin +# +# This file is part of GNU Mcron. +# +# GNU Mcron is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNU Mcron is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Mcron. If not, see . AC_PREREQ(2.61) AC_INIT([GNU Mcron], [1.0.8], [bug-mcron@gnu.org]) diff --git a/src/mcron/base.scm b/src/mcron/base.scm index b779c8a..b607c05 100644 --- a/src/mcron/base.scm +++ b/src/mcron/base.scm @@ -1,23 +1,22 @@ -;; Copyright (C) 2016 Ludovic Courtès -;; Copyright (C) 2015, 2016 Mathieu Lirzin -;; Copyright (C) 2003 Dale Mellor -;; -;; This file is part of GNU mcron. -;; -;; GNU mcron is free software: you can redistribute it and/or modify it under -;; the terms of the GNU General Public License as published by the Free -;; Software Foundation, either version 3 of the License, or (at your option) -;; any later version. -;; -;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT -;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -;; more details. -;; -;; You should have received a copy of the GNU General Public License along -;; with GNU mcron. If not, see . - - +;;;; base.scm -- core procedures +;;; Copyright © 2003 Dale Mellor +;;; Copyright © 2015, 2016 Mathieu Lirzin +;;; Copyright © 2016 Ludovic Courtès +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . (define-module (mcron base) #:use-module (ice-9 match) diff --git a/src/mcron/config.scm.in b/src/mcron/config.scm.in index db2bc32..2b0bc7f 100644 --- a/src/mcron/config.scm.in +++ b/src/mcron/config.scm.in @@ -1,25 +1,21 @@ -;; -*-scheme-*- - -;; Copyright (C) 2015 Mathieu Lirzin -;; Copyright (C) 2003 Dale Mellor -;; -;; This file is part of GNU mcron. -;; -;; GNU mcron is free software: you can redistribute it and/or modify it under -;; the terms of the GNU General Public License as published by the Free -;; Software Foundation, either version 3 of the License, or (at your option) -;; any later version. -;; -;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT -;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -;; more details. -;; -;; You should have received a copy of the GNU General Public License along -;; with GNU mcron. If not, see . - - -;; Some constants set by the configuration process. +;;;; config.scm -- variables defined at configure time +;;; Copyright © 2003 Dale Mellor +;;; Copyright © 2015, 2016 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . (define-module (mcron config)) diff --git a/src/mcron/environment.scm b/src/mcron/environment.scm index b563d55..f6b9637 100644 --- a/src/mcron/environment.scm +++ b/src/mcron/environment.scm @@ -1,35 +1,35 @@ -;; Copyright (C) 2015, 2016 Mathieu Lirzin -;; Copyright (C) 2003 Dale Mellor -;; -;; This file is part of GNU mcron. -;; -;; GNU mcron is free software: you can redistribute it and/or modify it under -;; the terms of the GNU General Public License as published by the Free -;; Software Foundation, either version 3 of the License, or (at your option) -;; any later version. -;; -;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT -;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -;; more details. -;; -;; You should have received a copy of the GNU General Public License along -;; with GNU mcron. If not, see . - - - -;; This file defines the variable current-environment-mods, and the procedures -;; append-environment-mods (which is available to user configuration files), -;; clear-environment-mods and modify-environment. The idea is that the -;; current-environment-mods is a list of pairs of environment names and values, -;; and represents the cumulated environment settings in a configuration -;; file. When a job definition is seen in a configuration file, the -;; current-environment-mods are copied into the internal job description, and -;; when the job actually runs these environment modifications are applied to -;; the UNIX environment in which the job runs. - - +;;;; environment.scm -- interact with the job process environment +;;; Copyright © 2003 Dale Mellor +;;; Copyright © 2015, 2016 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . +;;;; Commentary: +;;; +;;; Define the variable current-environment-mods, and the procedures +;;; append-environment-mods (which is available to user configuration files), +;;; clear-environment-mods and modify-environment. The idea is that the +;;; current-environment-mods is a list of pairs of environment names and +;;; values, and represents the cumulated environment settings in a +;;; configuration file. When a job definition is seen in a configuration file, +;;; the current-environment-mods are copied into the internal job description, +;;; and when the job actually runs these environment modifications are applied +;;; to the UNIX environment in which the job runs. +;;; +;;;; Code: (define-module (mcron environment) #:export (modify-environment diff --git a/src/mcron/job-specifier.scm b/src/mcron/job-specifier.scm index 5d60484..d4c05bd 100644 --- a/src/mcron/job-specifier.scm +++ b/src/mcron/job-specifier.scm @@ -1,28 +1,30 @@ -;; Copyright (C) 2003 Dale Mellor -;; Copyright (C) 2016 Mathieu Lirzin -;; -;; This file is part of GNU mcron. -;; -;; GNU mcron is free software: you can redistribute it and/or modify it under -;; the terms of the GNU General Public License as published by the Free -;; Software Foundation, either version 3 of the License, or (at your option) -;; any later version. -;; -;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT -;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -;; more details. -;; -;; You should have received a copy of the GNU General Public License along -;; with GNU mcron. If not, see . +;;;; job-specifier.scm -- public interface for defining jobs +;;; Copyright © 2003 Dale Mellor +;;; Copyright © 2016 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . - - -;; This module defines all the functions that can be used by scheme mcron -;; configuration files, namely the procedures for working out next times, the -;; job procedure for registering new jobs (actually a wrapper around the -;; base add-job function), and the procedure for declaring environment -;; modifications. +;;;; Commentary: +;;; +;;; Define all the functions that can be used by scheme Mcron configuration +;;; files, namely the procedures for working out next times, the job procedure +;;; for registering new jobs (actually a wrapper around the base add-job +;;; function), and the procedure for declaring environment modifications. +;;; +;;;; Code: (define-module (mcron job-specifier) #:use-module (ice-9 match) diff --git a/src/mcron/main.scm b/src/mcron/main.scm index 1faa1ae..74b49e5 100644 --- a/src/mcron/main.scm +++ b/src/mcron/main.scm @@ -1,20 +1,21 @@ -;; Copyright (C) 2015, 2016 Mathieu Lirzin -;; Copyright (C) 2003, 2012 Dale Mellor -;; -;; This file is part of GNU mcron. -;; -;; GNU mcron is free software: you can redistribute it and/or modify it under -;; the terms of the GNU General Public License as published by the Free -;; Software Foundation, either version 3 of the License, or (at your option) -;; any later version. -;; -;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT -;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -;; more details. -;; -;; You should have received a copy of the GNU General Public License along -;; with GNU mcron. If not, see . +;;; main.scm -- helper procedures +;;; Copyright © 2003, 2012 Dale Mellor +;;; Copyright © 2015, 2016 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . (define-module (mcron main) #:use-module (ice-9 getopt-long) diff --git a/src/mcron/redirect.scm b/src/mcron/redirect.scm index af763cb..7474c4a 100644 --- a/src/mcron/redirect.scm +++ b/src/mcron/redirect.scm @@ -1,33 +1,36 @@ -;; Copyright (C) 2003 Dale Mellor -;; -;; This file is part of GNU mcron. -;; -;; GNU mcron is free software: you can redistribute it and/or modify it under -;; the terms of the GNU General Public License as published by the Free -;; Software Foundation, either version 3 of the License, or (at your option) -;; any later version. -;; -;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT -;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -;; more details. -;; -;; You should have received a copy of the GNU General Public License along -;; with GNU mcron. If not, see . +;;;; redirect.scm -- modify job outputs +;;; Copyright © 2003 Dale Mellor +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . - - -;; This module provides the (with-mail-out action . user) procedure. This -;; procedure runs the action in a child process, allowing the user control over -;; the input and output (including standard error). The input is governed (only -;; in the case of a string action) by the placing of percentage signs in the -;; string; the first delimits the true action from the standard input, and -;; subsequent ones denote newlines to be placed into the input. The output (if -;; there actually is any) is controlled by the MAILTO environment variable. If -;; this is not defined, output is e-mailed to the user passed as argument, if -;; any, or else the owner of the action; if defined but empty then any output is -;; sunk to /dev/null; otherwise output is e-mailed to the address held in the -;; MAILTO variable. +;;;; Commentary: +;;; +;;; Provide the (with-mail-out action . user) procedure. This procedure runs +;;; the action in a child process, allowing the user control over the input +;;; and output (including standard error). The input is governed (only in the +;;; case of a string action) by the placing of percentage signs in the string; +;;; the first delimits the true action from the standard input, and subsequent +;;; ones denote newlines to be placed into the input. The output (if there +;;; actually is any) is controlled by the MAILTO environment variable. If +;;; this is not defined, output is e-mailed to the user passed as argument, if +;;; any, or else the owner of the action; if defined but empty then any output +;;; is sunk to /dev/null; otherwise output is e-mailed to the address held in +;;; the MAILTO variable. +;;; +;;;; Code: (define-module (mcron redirect) #:export (with-mail-out) diff --git a/src/mcron/vixie-specification.scm b/src/mcron/vixie-specification.scm index f055383..4356db7 100644 --- a/src/mcron/vixie-specification.scm +++ b/src/mcron/vixie-specification.scm @@ -1,27 +1,30 @@ -;; Copyright (C) 2003 Dale Mellor -;; -;; This file is part of GNU mcron. -;; -;; GNU mcron is free software: you can redistribute it and/or modify it under -;; the terms of the GNU General Public License as published by the Free -;; Software Foundation, either version 3 of the License, or (at your option) -;; any later version. -;; -;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT -;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -;; more details. -;; -;; You should have received a copy of the GNU General Public License along -;; with GNU mcron. If not, see . +;;;; vixie-specification.scm -- read Vixie-sytle configuration file +;;; Copyright © 2003 Dale Mellor +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . - - -;; This file provides methods for reading a complete Vixie-style configuration -;; file, either from a real file or an already opened port. It also exposes the -;; method for parsing the time-specification part of a Vixie string, so that -;; these can be used to form the next-time-function of a job in a Guile -;; configuration file. +;;;; Commentary: +;;; +;;; Methods for reading a complete Vixie-style configuration file, either from +;;; a real file or an already opened port. It also exposes the method for +;;; parsing the time-specification part of a Vixie string, so that these can +;;; be used to form the next-time-function of a job in a Guile configuration +;;; file. +;;; +;;;; Code: (define-module (mcron vixie-specification) #:export (parse-user-vixie-line diff --git a/src/mcron/vixie-time.scm b/src/mcron/vixie-time.scm index a91fa89..f734600 100644 --- a/src/mcron/vixie-time.scm +++ b/src/mcron/vixie-time.scm @@ -1,19 +1,20 @@ -;; Copyright (C) 2003 Dale Mellor -;; -;; This file is part of GNU mcron. -;; -;; GNU mcron is free software: you can redistribute it and/or modify it under -;; the terms of the GNU General Public License as published by the Free -;; Software Foundation, either version 3 of the License, or (at your option) -;; any later version. -;; -;; GNU mcron is distributed in the hope that it will be useful, but WITHOUT -;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -;; more details. -;; -;; You should have received a copy of the GNU General Public License along -;; with GNU mcron. If not, see . +;;;; vixie-time.scm -- parse Vixie-style times +;;; Copyright © 2003 Dale Mellor +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . (define-module (mcron vixie-time) #:use-module (ice-9 regex) diff --git a/src/wrapper.c b/src/wrapper.c index a5b46db..bb7932e 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -1,6 +1,6 @@ /* wrapper.c -- C code booting Guile - Copyright (C) 2003, 2014 Dale Mellor - Copyright (C) 2015, 2016 Mathieu Lirzin + Copyright © 2003, 2014 Dale Mellor + Copyright © 2015, 2016 Mathieu Lirzin This file is part of GNU Mcron. From 6a91b6fb3ef229689447a171e28e8d2c23a26bd0 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 18 Jul 2016 17:46:30 +0200 Subject: [PATCH 104/239] maint: Update AUTHORS. * AUTHORS: Add 'Sergey Poznyakoff' and 'Mathieu Lirzin'. --- AUTHORS | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/AUTHORS b/AUTHORS index 821f761..ed0888b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,18 +1,3 @@ -Authors of GNU mcron. - - Copyright (C) 2003, 2005, 2006 Dale Mellor - - Copying and distribution of this file, with or without modification, - are permitted in any medium without royalty provided the copyright - notice and this notice are preserved. - - - -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. +Dale Mellor +Mathieu Lirzin +Sergey Poznyakoff From 2c9139f6230b0931f7bf06fce0f7f6c0db8b1daf Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 18 Jul 2016 17:59:37 +0200 Subject: [PATCH 105/239] maint: Delete BUGS. * BUGS: Delete. * Makefile.am (EXTRA_DIST): Adapt. * README: Likewise. --- BUGS | 16 ---------------- Makefile.am | 2 +- README | 14 ++++++-------- 3 files changed, 7 insertions(+), 25 deletions(-) delete mode 100644 BUGS diff --git a/BUGS b/BUGS deleted file mode 100644 index 9aaa710..0000000 --- a/BUGS +++ /dev/null @@ -1,16 +0,0 @@ -GNU mcron --- BUGS -*-text-*- - - Copyright (C) 2003, 2005, 2006 Dale Mellor - - Copying and distribution of this file, with or without modification, - are permitted in any medium without royalty provided the copyright - notice and this notice are preserved. - - - -Please send bug reports to bug-mcron@gnu.org. - - -The currently-known bugs are:- - - -NONE- diff --git a/Makefile.am b/Makefile.am index 52a8499..77c9b28 100644 --- a/Makefile.am +++ b/Makefile.am @@ -137,7 +137,7 @@ uninstall-hook: rm -f $(fpp){cron,crontab}$(EXEEXT); \ fi -EXTRA_DIST = BUGS $(TESTS) +EXTRA_DIST = $(TESTS) MAINTAINERCLEANFILES = $(dist_man_MANS) DISTCLEANFILES = src/config.scm CLEANFILES = \ diff --git a/README b/README index 9f4f625..057f962 100644 --- a/README +++ b/README @@ -17,8 +17,6 @@ likely fail on others (but you never know...). ---------------------------------------------------------------------- IMPORTANT NOTICES -Read the BUGS file. - Do not (yet) install this software on a machine which relies for its functioning on its current set of crontabs. @@ -54,13 +52,13 @@ m.mcron, m.cron (or m.crond) and m.crontab. See the file INSTALL for generic building and installation instructions. -After installation, read the info file for full instructions for use (typing -`info mcron' at the command line should suffice). Notes for end users, -sysadmins, and developers who wish to incorporate mcron into their own programs -are included here. +After compilation, read the info file for full instructions for use (typing +'info -f doc/mcron.info' at the command line should suffice). Notes for end +users, sysadmins, and developers who wish to incorporate mcron into their own +programs are included here. -Known bugs are noted in the BUGS file, and features which might be implemented -sometime sooner or later are noted in the TODO file. +Features which might be implemented sometime sooner or later are noted in the +TODO file. Please send all other bug reports to bug-mcron@gnu.org. Other mailing lists you could subscribe to are help-mcron@gnu.org (for help and advice from the From 61f85be19da0e62c899e3b62da403480d881e9f9 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 23 Jul 2016 23:58:06 +0200 Subject: [PATCH 106/239] build: Rename (mcron main) to (mcron utils). * src/mcron/main.scm: Rename to ... * src/mcron/utils.scm: ... this. * src/mcron/scripts/cron.scm: Adapt. * src/mcron/scripts/crontab.scm: Likewise. * src/mcron/scripts/mcron.scm: Likewise. * Makefile.am (dist_mcronmodule_DATA): Likewise. --- Makefile.am | 2 +- src/mcron/scripts/cron.scm | 2 +- src/mcron/scripts/crontab.scm | 2 +- src/mcron/scripts/mcron.scm | 2 +- src/mcron/{main.scm => utils.scm} | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) rename src/mcron/{main.scm => utils.scm} (98%) diff --git a/Makefile.am b/Makefile.am index 77c9b28..109e27a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -40,8 +40,8 @@ dist_mcronmodule_DATA = \ src/mcron/base.scm \ src/mcron/environment.scm \ src/mcron/job-specifier.scm \ - src/mcron/main.scm \ src/mcron/redirect.scm \ + src/mcron/utils.scm \ src/mcron/vixie-specification.scm \ src/mcron/vixie-time.scm diff --git a/src/mcron/scripts/cron.scm b/src/mcron/scripts/cron.scm index dd8f5ad..d043d79 100644 --- a/src/mcron/scripts/cron.scm +++ b/src/mcron/scripts/cron.scm @@ -21,7 +21,7 @@ #:use-module (mcron base) #:use-module (mcron config) #:use-module (mcron job-specifier) - #:use-module (mcron main) + #:use-module (mcron utils) #:use-module (mcron vixie-specification) #:use-module (srfi srfi-2) #:export (main)) diff --git a/src/mcron/scripts/crontab.scm b/src/mcron/scripts/crontab.scm index 43ae8f6..cf6673a 100644 --- a/src/mcron/scripts/crontab.scm +++ b/src/mcron/scripts/crontab.scm @@ -20,7 +20,7 @@ (define-module (mcron scripts crontab) #:use-module (ice-9 rdelim) #:use-module (mcron config) - #:use-module (mcron main) + #:use-module (mcron utils) #:use-module (mcron vixie-specification) #:export (main)) diff --git a/src/mcron/scripts/mcron.scm b/src/mcron/scripts/mcron.scm index 30b2d2a..7b82cf3 100644 --- a/src/mcron/scripts/mcron.scm +++ b/src/mcron/scripts/mcron.scm @@ -21,7 +21,7 @@ #:use-module (mcron base) #:use-module (mcron config) #:use-module (mcron job-specifier) ;for user/system files - #:use-module (mcron main) + #:use-module (mcron utils) #:use-module (mcron vixie-specification) #:export (main)) diff --git a/src/mcron/main.scm b/src/mcron/utils.scm similarity index 98% rename from src/mcron/main.scm rename to src/mcron/utils.scm index 74b49e5..7b29971 100644 --- a/src/mcron/main.scm +++ b/src/mcron/utils.scm @@ -1,4 +1,4 @@ -;;; main.scm -- helper procedures +;;;; utils.scm -- helper procedures ;;; Copyright © 2003, 2012 Dale Mellor ;;; Copyright © 2015, 2016 Mathieu Lirzin ;;; @@ -17,7 +17,7 @@ ;;; You should have received a copy of the GNU General Public License ;;; along with GNU Mcron. If not, see . -(define-module (mcron main) +(define-module (mcron utils) #:use-module (ice-9 getopt-long) #:use-module (ice-9 rdelim) #:use-module (mcron config) From 2d6c072b47a72f9152b2d43d0ffa42f413f15713 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 24 Jul 2016 00:26:20 +0200 Subject: [PATCH 107/239] utils: for-each-file: Use named let. * src/mcron/utils.scm (for-each-file): Use named 'let' instead of 'do'. --- src/mcron/utils.scm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/mcron/utils.scm b/src/mcron/utils.scm index 7b29971..ce2610c 100644 --- a/src/mcron/utils.scm +++ b/src/mcron/utils.scm @@ -92,9 +92,12 @@ General help using GNU software: \n" PROC must be a procedure that take one file name argument. The return value is not specified" (let ((dir (opendir directory))) - (do ((file-name (readdir dir) (readdir dir))) - ((eof-object? file-name) (closedir dir)) - (proc file-name)))) + (let loop ((file-name (readdir dir))) + (if (eof-object? file-name) + (closedir dir) + (begin + (proc file-name) + (loop (readdir dir))))))) (define (process-update-request fdes-list) "Read a user name from the socket, dealing with the /etc/crontab special From d4b4ac5708385d500f566267719124c7c62572df Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 24 Jul 2016 00:38:21 +0200 Subject: [PATCH 108/239] utils: Remove unneeded 'stdin->string' procedure. * src/mcron/utils.scm: Re-export 'read-string'. (stdin->string): Delete. * src/mcron/scripts/crontab.scm (main): Use 'read-string' instead. * src/mcron/scripts/mcron.scm (process-user-file): Likewise. --- src/mcron/scripts/crontab.scm | 2 +- src/mcron/scripts/mcron.scm | 2 +- src/mcron/utils.scm | 10 ++-------- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/mcron/scripts/crontab.scm b/src/mcron/scripts/crontab.scm index cf6673a..502fec6 100644 --- a/src/mcron/scripts/crontab.scm +++ b/src/mcron/scripts/crontab.scm @@ -210,7 +210,7 @@ (let ((input-file (car (option-ref opts '() '())))) (catch-mcron-error (if (string=? input-file "-") - (let ((input-string (stdin->string))) + (let ((input-string (read-string))) (read-vixie-port (open-input-string input-string)) (with-output-to-file crontab-file (λ () (display input-string)))) diff --git a/src/mcron/scripts/mcron.scm b/src/mcron/scripts/mcron.scm index 7b82cf3..b6c7729 100644 --- a/src/mcron/scripts/mcron.scm +++ b/src/mcron/scripts/mcron.scm @@ -63,7 +63,7 @@ silently ignored." (cond ((string=? "-" file-name) (if (string=? input "vixie") (read-vixie-port (current-input-port)) - (eval-string (stdin->string)))) + (eval-string (read-string)))) ((or guile-syntax? (regexp-exec guile-regexp file-name)) (load file-name)) ((regexp-exec vixie-regexp file-name) diff --git a/src/mcron/utils.scm b/src/mcron/utils.scm index ce2610c..062e756 100644 --- a/src/mcron/utils.scm +++ b/src/mcron/utils.scm @@ -29,10 +29,10 @@ parse-args show-version show-package-information - stdin->string for-each-file process-update-request) - #:re-export (option-ref)) + #:re-export (option-ref + read-string)) (define (mcron-error exit-code . rest) "Print an error message (made up from the parts of REST), and if the @@ -81,12 +81,6 @@ General help using GNU software: \n" config-package-name config-package-url)) -(define (stdin->string) - "Return standard input as a string." - (with-output-to-string (lambda () (do ((in (read-char) (read-char))) - ((eof-object? in)) - (display in))))) - (define (for-each-file proc directory) "Apply PROC to each file in DIRECTORY. DIRECTORY must be a valid directory name. PROC must be a procedure that take one file name argument. The return value From 4d518fd3f114a397fe6a3380513409293a721ab8 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 24 Jul 2016 01:05:29 +0200 Subject: [PATCH 109/239] all: Gather module imports. * src/mcron/base.scm: Gather module imports. * src/mcron/redirect.scm: Likewise. * src/mcron/vixie-specification.scm: Likewise. * src/mcron/vixie-time.scm: Likewise. --- src/mcron/base.scm | 28 ++++++++++++---------------- src/mcron/redirect.scm | 11 ++++------- src/mcron/vixie-specification.scm | 22 ++++++++++------------ src/mcron/vixie-time.scm | 2 -- 4 files changed, 26 insertions(+), 37 deletions(-) diff --git a/src/mcron/base.scm b/src/mcron/base.scm index b607c05..a133f66 100644 --- a/src/mcron/base.scm +++ b/src/mcron/base.scm @@ -21,23 +21,19 @@ (define-module (mcron base) #:use-module (ice-9 match) #:use-module (mcron environment) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-2) #:use-module (srfi srfi-9) - #:export (add-job - remove-user-jobs - get-schedule - run-job-loop - ;; These three are deprecated and not documented. - use-system-job-list - use-user-job-list - clear-system-jobs) - #:re-export (clear-environment-mods - append-environment-mods)) - - -(use-modules (srfi srfi-1) ;; For remove. - (srfi srfi-2)) ;; For and-let*. - - + #:export (add-job + remove-user-jobs + get-schedule + run-job-loop + ;; Deprecated and undocumented procedures. + use-system-job-list + use-user-job-list + clear-system-jobs) + #:re-export (clear-environment-mods + append-environment-mods)) ;; The list of all jobs known to the system. Each element of the list is ;; diff --git a/src/mcron/redirect.scm b/src/mcron/redirect.scm index 7474c4a..6711407 100644 --- a/src/mcron/redirect.scm +++ b/src/mcron/redirect.scm @@ -33,12 +33,11 @@ ;;;; Code: (define-module (mcron redirect) - #:export (with-mail-out) + #:use-module (ice-9 popen) #:use-module (ice-9 regex) - #:use-module ((mcron config) :select (config-sendmail)) - #:use-module (mcron vixie-time)) - - + #:use-module (mcron config) + #:use-module (mcron vixie-time) + #:export (with-mail-out)) ;; An action string consists of a sequence of characters forming a command ;; executable by the shell, possibly followed by an non-escaped percentage @@ -63,8 +62,6 @@ ;; the string, and output (including the error output) being sent to a pipe ;; opened on a mail transport. -(use-modules (ice-9 popen)) - (define (with-mail-out action . user) ;; Determine the name of the user who is to recieve the mail, looking for a diff --git a/src/mcron/vixie-specification.scm b/src/mcron/vixie-specification.scm index 4356db7..e040fe0 100644 --- a/src/mcron/vixie-specification.scm +++ b/src/mcron/vixie-specification.scm @@ -27,22 +27,20 @@ ;;;; Code: (define-module (mcron vixie-specification) + #:use-module (ice-9 regex) + #:use-module (ice-9 rdelim) + #:use-module (mcron base) + #:use-module (mcron config) + #:use-module (mcron job-specifier) + #:use-module (mcron redirect) + #:use-module (mcron vixie-time) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-2) #:export (parse-user-vixie-line parse-system-vixie-line read-vixie-port read-vixie-file - check-system-crontab) - #:use-module ((mcron config) :select (config-socket-file)) - #:use-module (mcron base) - #:use-module (mcron job-specifier) - #:use-module (mcron redirect) - #:use-module (mcron vixie-time)) - - -(use-modules (ice-9 regex) (ice-9 rdelim) - (srfi srfi-1) (srfi srfi-2) (srfi srfi-13) (srfi srfi-14)) - - + check-system-crontab)) ;; A line in a Vixie-style crontab file which gives a command specification ;; carries two pieces of information: a time specification consisting of five diff --git a/src/mcron/vixie-time.scm b/src/mcron/vixie-time.scm index f734600..c4d6bd9 100644 --- a/src/mcron/vixie-time.scm +++ b/src/mcron/vixie-time.scm @@ -20,8 +20,6 @@ #:use-module (ice-9 regex) #:use-module (mcron job-specifier) #:use-module (srfi srfi-1) - #:use-module (srfi srfi-13) - #:use-module (srfi srfi-14) #:export (parse-vixie-time)) ;; In Vixie-style time specifications three-letter symbols are allowed to stand From c1d2c765ef0afb4ea7546675f7ddbffc02d0dc97 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 24 Jul 2016 01:09:14 +0200 Subject: [PATCH 110/239] vixie-specification: Do not use 'and-let*'. * src/mcron/vixie-specification.scm (parse-vixie-environment): Use 'and=>' instead of 'and-let*' --- src/mcron/vixie-specification.scm | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/mcron/vixie-specification.scm b/src/mcron/vixie-specification.scm index e040fe0..cf2679a 100644 --- a/src/mcron/vixie-specification.scm +++ b/src/mcron/vixie-specification.scm @@ -35,7 +35,6 @@ #:use-module (mcron redirect) #:use-module (mcron vixie-time) #:use-module (srfi srfi-1) - #:use-module (srfi srfi-2) #:export (parse-user-vixie-line parse-system-vixie-line read-vixie-port @@ -109,11 +108,9 @@ (if match (append-environment-mods (match:substring match 1) (match:substring match 2)) - (and-let* ((match (regexp-exec parse-vixie-environment-regexp4 string))) - (append-environment-mods (match:substring match 1) #f))))) - - - + (and=> (regexp-exec parse-vixie-environment-regexp4 string) + (λ (match) + (append-environment-mods (match:substring match 1) #f)))))) ;; The next procedure reads an entire Vixie-style file. For each line in the ;; file there are three possibilities (after continuation lines have been From 5e6233a58dab5b22cadffdfd16505a440808a659 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 24 Jul 2016 01:45:45 +0200 Subject: [PATCH 111/239] base: find-next-jobs: Use functional style. * src/mcron/base.scm (find-next-jobs): Rewrite it using functional style. Add docstring. --- src/mcron/base.scm | 67 +++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 39 deletions(-) diff --git a/src/mcron/base.scm b/src/mcron/base.scm index a133f66..c100b4f 100644 --- a/src/mcron/base.scm +++ b/src/mcron/base.scm @@ -105,47 +105,36 @@ (set! user-job-list (cons entry user-job-list)) (set! system-job-list (cons entry system-job-list))))) - - -;; Procedure to locate the jobs in the global job-list with the lowest -;; (soonest) next-times. These are the jobs for which we must schedule the mcron -;; program (under any personality) to next wake up. The return value is a cons -;; cell consisting of the next time (maintained in the next-time variable) and a -;; list of the job entries that are to run at this time (maintained in the -;; next-jobs-list variable). -;; -;; The procedure works by first obtaining the time of the first job on the list, -;; and setting this job in the next-jobs-list. Then for each other entry on the -;; job-list, either the job runs earlier than any other that have been scanned, -;; in which case the next-time and next-jobs-list are re-initialized to -;; accomodate, or the job runs at the same time as the next job, in which case -;; the next-jobs-list is simply augmented with the new job, or else the job runs -;; later than others noted in which case we ignore it for now and continue to -;; recurse the list. - (define (find-next-jobs) - (let ((job-list (append system-job-list user-job-list))) - - (if (null? job-list) - - '(#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))))) - + "Procedure to locate the jobs in the global job-list with the +lowest (soonest) next-times. These are the jobs for which we must schedule +the mcron program (under any personality) to next wake up. The return value +is a cons cell consisting of the next time (maintained in the next-time +variable) and a list of the job entries that are to run at this +time (maintained in the next-jobs-list variable). +The procedure works by first obtaining the time of the first job on the list, +and setting this job in the next-jobs-list. Then for each other entry on the +job-list, either the job runs earlier than any other that have been scanned, +in which case the next-time and next-jobs-list are re-initialized to +accomodate, or the job runs at the same time as the next job, in which case +the next-jobs-list is simply augmented with the new job, or else the job runs +later than others noted in which case we ignore it for now and continue to +recurse the list." + (let loop ((jobs (append system-job-list user-job-list)) + (next-time (inf)) + (next-jobs '())) + (match jobs + (() + (cons (and (finite? next-time) next-time) next-jobs)) + ((job . rest) + (let ((this-time (job:next-time job))) + (cond ((< this-time next-time) + (loop rest this-time (list job))) + ((= this-time next-time) + (loop rest next-time (cons job next-jobs))) + (else + (loop rest next-time next-jobs)))))))) ;; Create a string containing a textual list of the next count jobs to run. ;; From a3051133c0370abcbff266441e177ce81920457a Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 28 Dec 2016 23:06:03 +0100 Subject: [PATCH 112/239] maint: Generate version number. * build-aux/git-version-gen: New script. * configure.ac (AC_INIT): Use it. (AC_REQUIRE_AUX_FILE): Distribute it. * Makefile.am (.version): New target. (BUILT_SOURCES, EXTRA_DIST): Add it. (dist-hook): Generate ".tarball-version". * .gitignore: Update. --- .gitignore | 1 + Makefile.am | 10 +- build-aux/git-version-gen | 226 ++++++++++++++++++++++++++++++++++++++ configure.ac | 5 +- 4 files changed, 240 insertions(+), 2 deletions(-) create mode 100755 build-aux/git-version-gen diff --git a/.gitignore b/.gitignore index cc8e31d..09579ee 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ /doc/version.texi /mcron /mdate-sh +/.version INSTALL Makefile Makefile.in diff --git a/Makefile.am b/Makefile.am index 109e27a..a1d6be4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -97,7 +97,12 @@ TESTS = \ SUFFIXES = .go noinst_SCRIPTS = pre-inst-env +BUILT_SOURCES= .version +.version: + $(AM_V_GEN)echo $(VERSION) > $@-t && mv $@-t $@ + dist-hook: gen-ChangeLog + $(AM_V_GEN)echo $(VERSION) > $(distdir)/.tarball-version gen_start_date = 2015-06-26 .PHONY: gen-ChangeLog @@ -137,7 +142,10 @@ uninstall-hook: rm -f $(fpp){cron,crontab}$(EXEEXT); \ fi -EXTRA_DIST = $(TESTS) +EXTRA_DIST = \ + .version \ + $(TESTS) + MAINTAINERCLEANFILES = $(dist_man_MANS) DISTCLEANFILES = src/config.scm CLEANFILES = \ diff --git a/build-aux/git-version-gen b/build-aux/git-version-gen new file mode 100755 index 0000000..bd2c4b6 --- /dev/null +++ b/build-aux/git-version-gen @@ -0,0 +1,226 @@ +#!/bin/sh +# Print a version string. +scriptversion=2016-05-08.18; # UTC + +# Copyright (C) 2007-2016 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/. +# It may be run two ways: +# - from a git repository in which the "git describe" command below +# produces useful output (thus requiring at least one signed tag) +# - from a non-git-repo directory containing a .tarball-version file, which +# presumes this script is invoked like "./git-version-gen .tarball-version". + +# In order to use intra-version strings in your project, you will need two +# separate generated version string files: +# +# .tarball-version - present only in a distribution tarball, and not in +# a checked-out repository. Created with contents that were learned at +# the last time autoconf was run, and used by git-version-gen. Must not +# be present in either $(srcdir) or $(builddir) for git-version-gen to +# give accurate answers during normal development with a checked out tree, +# but must be present in a tarball when there is no version control system. +# Therefore, it cannot be used in any dependencies. GNUmakefile has +# hooks to force a reconfigure at distribution time to get the value +# correct, without penalizing normal development with extra reconfigures. +# +# .version - present in a checked-out repository and in a distribution +# tarball. Usable in dependencies, particularly for files that don't +# want to depend on config.h but do want to track version changes. +# Delete this file prior to any autoconf run where you want to rebuild +# files to pick up a version string change; and leave it stale to +# minimize rebuild time after unrelated changes to configure sources. +# +# As with any generated file in a VC'd directory, you should add +# /.version to .gitignore, so that you don't accidentally commit it. +# .tarball-version is never generated in a VC'd directory, so needn't +# be listed there. +# +# Use the following line in your configure.ac, so that $(VERSION) will +# automatically be up-to-date each time configure is run (and note that +# since configure.ac no longer includes a version string, Makefile rules +# should not depend on configure.ac for version updates). +# +# AC_INIT([GNU project], +# m4_esyscmd([build-aux/git-version-gen .tarball-version]), +# [bug-project@example]) +# +# Then use the following lines in your Makefile.am, so that .version +# will be present for dependencies, and so that .version and +# .tarball-version will exist in distribution tarballs. +# +# EXTRA_DIST = $(top_srcdir)/.version +# BUILT_SOURCES = $(top_srcdir)/.version +# $(top_srcdir)/.version: +# echo $(VERSION) > $@-t && mv $@-t $@ +# dist-hook: +# echo $(VERSION) > $(distdir)/.tarball-version + + +me=$0 + +version="git-version-gen $scriptversion + +Copyright 2011 Free Software Foundation, Inc. +There is NO warranty. You may redistribute this software +under the terms of the GNU General Public License. +For more information about these matters, see the files named COPYING." + +usage="\ +Usage: $me [OPTION]... \$srcdir/.tarball-version [TAG-NORMALIZATION-SED-SCRIPT] +Print a version string. + +Options: + + --prefix PREFIX prefix of git tags (default 'v') + --fallback VERSION + fallback version to use if \"git --version\" fails + + --help display this help and exit + --version output version information and exit + +Running without arguments will suffice in most cases." + +prefix=v +fallback= + +while test $# -gt 0; do + case $1 in + --help) echo "$usage"; exit 0;; + --version) echo "$version"; exit 0;; + --prefix) shift; prefix=${1?};; + --fallback) shift; fallback=${1?};; + -*) + echo "$0: Unknown option '$1'." >&2 + echo "$0: Try '--help' for more information." >&2 + exit 1;; + *) + if test "x$tarball_version_file" = x; then + tarball_version_file="$1" + elif test "x$tag_sed_script" = x; then + tag_sed_script="$1" + else + echo "$0: extra non-option argument '$1'." >&2 + exit 1 + fi;; + esac + shift +done + +if test "x$tarball_version_file" = x; then + echo "$usage" + exit 1 +fi + +tag_sed_script="${tag_sed_script:-s/x/x/}" + +nl=' +' + +# Avoid meddling by environment variable of the same name. +v= +v_from_git= + +# First see if there is a tarball-only version file. +# then try "git describe", then default. +if test -f $tarball_version_file +then + v=`cat $tarball_version_file` || v= + case $v in + *$nl*) v= ;; # reject multi-line output + [0-9]*) ;; + *) v= ;; + esac + test "x$v" = x \ + && echo "$0: WARNING: $tarball_version_file is missing or damaged" 1>&2 +fi + +if test "x$v" != x +then + : # use $v +# Otherwise, if there is at least one git commit involving the working +# directory, and "git describe" output looks sensible, use that to +# derive a version string. +elif test "`git log -1 --pretty=format:x . 2>&1`" = x \ + && v=`git describe --abbrev=4 --match="$prefix*" HEAD 2>/dev/null \ + || git describe --abbrev=4 HEAD 2>/dev/null` \ + && v=`printf '%s\n' "$v" | sed "$tag_sed_script"` \ + && case $v in + $prefix[0-9]*) ;; + *) (exit 1) ;; + esac +then + # Is this a new git that lists number of commits since the last + # tag or the previous older version that did not? + # Newer: v6.10-77-g0f8faeb + # Older: v6.10-g0f8faeb + case $v in + *-*-*) : git describe is okay three part flavor ;; + *-*) + : git describe is older two part flavor + # Recreate the number of commits and rewrite such that the + # result is the same as if we were using the newer version + # of git describe. + vtag=`echo "$v" | sed 's/-.*//'` + commit_list=`git rev-list "$vtag"..HEAD 2>/dev/null` \ + || { commit_list=failed; + echo "$0: WARNING: git rev-list failed" 1>&2; } + numcommits=`echo "$commit_list" | wc -l` + v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`; + test "$commit_list" = failed && v=UNKNOWN + ;; + esac + + # Change the first '-' to a '.', so version-comparing tools work properly. + # Remove the "g" in git describe's output string, to save a byte. + v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`; + v_from_git=1 +elif test "x$fallback" = x || git --version >/dev/null 2>&1; then + v=UNKNOWN +else + v=$fallback +fi + +v=`echo "$v" |sed "s/^$prefix//"` + +# Test whether to append the "-dirty" suffix only if the version +# string we're using came from git. I.e., skip the test if it's "UNKNOWN" +# or if it came from .tarball-version. +if test "x$v_from_git" != x; then + # Don't declare a version "dirty" merely because a time stamp has changed. + git update-index --refresh > /dev/null 2>&1 + + dirty=`exec 2>/dev/null;git diff-index --name-only HEAD` || dirty= + case "$dirty" in + '') ;; + *) # Append the suffix only if there isn't one already. + case $v in + *-dirty) ;; + *) v="$v-dirty" ;; + esac ;; + esac +fi + +# Omit the trailing newline, so that m4_esyscmd can use the result directly. +printf %s "$v" + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/configure.ac b/configure.ac index 97c900b..5940555 100644 --- a/configure.ac +++ b/configure.ac @@ -19,10 +19,13 @@ # along with GNU Mcron. If not, see . AC_PREREQ(2.61) -AC_INIT([GNU Mcron], [1.0.8], [bug-mcron@gnu.org]) +AC_INIT([GNU Mcron], + m4_esyscmd([build-aux/git-version-gen .tarball-version]), + [bug-mcron@gnu.org]) AC_CONFIG_SRCDIR([src/wrapper.c]) AC_CONFIG_AUX_DIR([build-aux]) AC_REQUIRE_AUX_FILE([test-driver.scm]) +AC_REQUIRE_AUX_FILE([git-version-gen]) AM_INIT_AUTOMAKE([subdir-objects -Wall -Wno-override]) AM_SILENT_RULES([yes]) # enables silent rules by default From ea648c07305cd3447b8ec71f2dcadf7e5e1796fa Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 28 Dec 2016 23:30:18 +0100 Subject: [PATCH 113/239] build: Move executable to "bin" directory. * Makefile.am (bin_PROGRAMS, sbin_PROGRAMS): Prepend "bin/" to every program. (mcron_SOURCES, mcron_CPPFLAGS, mcron_DEPENDENCIES): Rename to ... (bin_mcron_SOURCES, bin_mcron_CPPFLAGS, bin_mcron_DEPENDENCIES): ... this. (cron_SOURCES, cron_CPPFLAGS, cron_DEPENDENCIES): Rename to ... (bin_cron_SOURCES, bin_cron_CPPFLAGS, bin_cron_DEPENDENCIES): ... this. (crontab_SOURCES, crontab_CPPFLAGS, crontab_DEPENDENCIES): Rename to ... (bin_crontab_SOURCES, bin_crontab_CPPFLAGS, bin_crontab_DEPENDENCIES): ($(srcdir)/doc/cron.8, $(srcdir)/doc/crontab.1, $(srcdir)/doc/mcron.1): Update prerequisite. * build-aux/pre-inst-env.in (PATH): Use "bin" directory. * .gitignore: Update. --- .gitignore | 6 +++--- Makefile.am | 28 ++++++++++++++-------------- build-aux/pre-inst-env.in | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 09579ee..44aed99 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ *~ .deps .dirstamp +/bin/cron +/bin/crontab +/bin/mcron /build-aux/compile /build-aux/config.guess /build-aux/config.sub @@ -13,8 +16,6 @@ /build-aux/mdate-sh /build-aux/missing /build-aux/texinfo.tex -/cron -/crontab /doc/config.texi /doc/cron.8 /doc/crontab.1 @@ -22,7 +23,6 @@ /doc/mcron.info /doc/stamp-vti /doc/version.texi -/mcron /mdate-sh /.version INSTALL diff --git a/Makefile.am b/Makefile.am index a1d6be4..d31eacb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,24 +17,24 @@ # You should have received a copy of the GNU General Public License # along with GNU Mcron. If not, see . -bin_PROGRAMS = mcron crontab -sbin_PROGRAMS = cron +bin_PROGRAMS = bin/mcron bin/crontab +sbin_PROGRAMS = bin/cron AM_CPPFLAGS = -DPACKAGE_LOAD_PATH=\"$(moduledir)\" AM_CFLAGS = @GUILE_CFLAGS@ LDADD = @GUILE_LIBS@ -mcron_SOURCES = src/wrapper.c -mcron_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"mcron\"" -mcron_DEPENDENCIES = $(modules:%.scm=%.go) +bin_mcron_SOURCES = src/wrapper.c +bin_mcron_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"mcron\"" +bin_mcron_DEPENDENCIES = $(modules:%.scm=%.go) -cron_SOURCES = src/wrapper.c -cron_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"cron\"" -cron_DEPENDENCIES = $(modules:%.scm=%.go) +bin_cron_SOURCES = src/wrapper.c +bin_cron_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"cron\"" +bin_cron_DEPENDENCIES = $(modules:%.scm=%.go) -crontab_SOURCES = src/wrapper.c -crontab_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"crontab\"" -crontab_DEPENDENCIES = $(modules:%.scm=%.go) +bin_crontab_SOURCES = src/wrapper.c +bin_crontab_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"crontab\"" +bin_crontab_DEPENDENCIES = $(modules:%.scm=%.go) dist_mcronmodule_DATA = \ src/mcron/base.scm \ @@ -180,13 +180,13 @@ gen_man = \ *) : ;; \ esac -$(srcdir)/doc/mcron.1: src/mcron/scripts/mcron.scm mcron +$(srcdir)/doc/mcron.1: src/mcron/scripts/mcron.scm bin/mcron -@prog="mcron"; man_section=1; $(gen_man) -$(srcdir)/doc/crontab.1: src/mcron/scripts/crontab.scm crontab +$(srcdir)/doc/crontab.1: src/mcron/scripts/crontab.scm bin/crontab -@prog="crontab"; man_section=1; $(gen_man) -$(srcdir)/doc/cron.8: src/mcron/scripts/cron.scm cron +$(srcdir)/doc/cron.8: src/mcron/scripts/cron.scm bin/cron -@prog="cron"; man_section=8; $(gen_man) ## -------------- ## diff --git a/build-aux/pre-inst-env.in b/build-aux/pre-inst-env.in index ea866ee..75a8d70 100644 --- a/build-aux/pre-inst-env.in +++ b/build-aux/pre-inst-env.in @@ -24,7 +24,7 @@ GUILE_LOAD_COMPILED_PATH="$abs_top_builddir/src${GUILE_LOAD_COMPILED_PATH:+:}$GU GUILE_LOAD_PATH="$abs_top_builddir/src:$abs_top_srcdir/src${GUILE_LOAD_PATH:+:}:$GUILE_LOAD_PATH" export GUILE_LOAD_COMPILED_PATH GUILE_LOAD_PATH -PATH="$abs_top_builddir:$PATH" +PATH="$abs_top_builddir/bin:$PATH" export PATH # Define $MCRON_UNINSTALLED to prevent 'mcron' from prepending @moduledir@ to From aaf1b08404b4f06ee31f1de06e8d40c74aa5f3ae Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 28 Dec 2016 23:13:30 +0100 Subject: [PATCH 114/239] build: Add "build-aux/guix.scm". * build-aux/guix.scm: New file. * Makefile.am (EXTRA_DIST): Add it. --- Makefile.am | 1 + build-aux/guix.scm | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 build-aux/guix.scm diff --git a/Makefile.am b/Makefile.am index d31eacb..b74238c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -143,6 +143,7 @@ uninstall-hook: fi EXTRA_DIST = \ + build-aux/guix.scm \ .version \ $(TESTS) diff --git a/build-aux/guix.scm b/build-aux/guix.scm new file mode 100644 index 0000000..d90e0be --- /dev/null +++ b/build-aux/guix.scm @@ -0,0 +1,66 @@ +;;;; guix.scm -- Guix package definition +;;; Copyright © 2016 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . + +(use-modules (ice-9 popen) + (ice-9 rdelim) + (gnu) + (guix) + (srfi srfi-1)) + +(define (keep-mcron-file? file stat) + ;; Return #t if FILE in Mcron repository must be kept, #f otherwise. FILE + ;; is an absolute file name and STAT is the result of 'lstat' applied to + ;; FILE. + (not (or (any (λ (str) (string-contains file str)) + '(".git" "autom4te" "Makefile.in" ".go" ".log" + "stamp-vti" ".dirstamp")) + (any (λ (str) (string-suffix? str file)) + '("trs""configure" "Makefile" "config.status" "pre-inst-env" + "aclocal.m4" "bin/cron" "bin/mcron" "bin/crontab" "config.cache" + "guix.scm"))))) + +(define %srcdir + (or (current-source-directory) ".")) + +(define (git-version-gen) + ;; Return a string containing Cuirass version number. + (let* ((cmd "git-version-gen .version") + (port (open-input-pipe (string-append %srcdir "/" cmd))) + (str (read-line port))) + (close-pipe port) + str)) + +(package + (inherit (specification->package "mcron2")) + (version (git-version-gen)) + (source (local-file (dirname %srcdir) #:recursive? #t + #:select? keep-mcron-file?)) + (arguments + '(#:phases + (modify-phases %standard-phases + (add-before 'configure 'bootstrap + (λ _ (zero? (system* "autoreconf" "-vfi"))))))) + (inputs + `(("guile" ,(specification->package "guile@2.0")))) + (native-inputs + `(("autoconf" ,(specification->package "autoconf")) + ("automake" ,(specification->package "automake")) + ("help2man" ,(specification->package "help2man")) + ("pkg-config" ,(specification->package "pkg-config")) + ("texinfo" ,(specification->package "texinfo")) + ("which" ,(specification->package "which"))))) From ba294d6a3ba4d086bc9571d62c705ab6eab200e3 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 28 Dec 2016 23:55:43 +0100 Subject: [PATCH 115/239] build: Use portable substitution references. * Makefile.am (bin_mcron_DEPENDENCIES, bin_cron_DEPENDENCIES) (bin_crontab_DEPENDENCIES, mcronmodule_DATA, mcronscript_DATA) (CLEANFILES): Use portable substitution references. --- Makefile.am | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index b74238c..45bb941 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,15 +26,15 @@ LDADD = @GUILE_LIBS@ bin_mcron_SOURCES = src/wrapper.c bin_mcron_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"mcron\"" -bin_mcron_DEPENDENCIES = $(modules:%.scm=%.go) +bin_mcron_DEPENDENCIES = $(modules:.scm=.go) bin_cron_SOURCES = src/wrapper.c bin_cron_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"cron\"" -bin_cron_DEPENDENCIES = $(modules:%.scm=%.go) +bin_cron_DEPENDENCIES = $(modules:.scm=.go) bin_crontab_SOURCES = src/wrapper.c bin_crontab_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"crontab\"" -bin_crontab_DEPENDENCIES = $(modules:%.scm=%.go) +bin_crontab_DEPENDENCIES = $(modules:.scm=.go) dist_mcronmodule_DATA = \ src/mcron/base.scm \ @@ -46,7 +46,7 @@ dist_mcronmodule_DATA = \ src/mcron/vixie-time.scm mcronmodule_DATA = \ - $(dist_mcronmodule_DATA:%.scm=%.go) \ + $(dist_mcronmodule_DATA:.scm=.go) \ src/mcron/config.scm \ src/mcron/config.go @@ -56,7 +56,7 @@ dist_mcronscript_DATA = \ src/mcron/scripts/crontab.scm \ src/mcron/scripts/mcron.scm -mcronscript_DATA = $(dist_mcronscript_DATA:%.scm=%.go) +mcronscript_DATA = $(dist_mcronscript_DATA:.scm=.go) modules = \ $(dist_mcronmodule_DATA) \ @@ -150,7 +150,7 @@ EXTRA_DIST = \ MAINTAINERCLEANFILES = $(dist_man_MANS) DISTCLEANFILES = src/config.scm CLEANFILES = \ - $(modules:%.scm=%.go) \ + $(modules:.scm=.go) \ src/mcron/config.go ## --------------- ## From 41b427e1b220389eccd65e436fc3452e2bc0215d Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 27 Sep 2017 23:10:29 +0200 Subject: [PATCH 116/239] Revert "Taken on board suggestions of Mathieu Lirzin as per e-mails to the bug-mcron@gnu.org mailing list around September 2015." This reverts commit c0a6eb14c257a47e9573631e5ac09e6528fba377. --- .gitignore | 13 +- AUTHORS | 5 +- ChangeLog | 41 +- TODO | 9 - configure.ac | 25 +- doc/fdl.texi | 505 ----------------------- doc/mcron.texi | 6 - makefile.am | 33 +- makefile.ed | 34 ++ mcron.c | 115 ------ mcron.c.template | 120 ++++++ scm/mcron/config.scm.in | 4 - scm/mcron/crontab.scm | 4 +- scm/mcron/environment.scm | 55 +-- scm/mcron/job-specifier.scm | 21 +- scm/mcron/main.scm | 653 ++++++++++++++++-------------- scm/mcron/makefile.am | 65 +-- scm/mcron/mcron-core.scm | 96 ++--- scm/mcron/redirect.scm | 1 - scm/mcron/vixie-specification.scm | 14 +- 20 files changed, 664 insertions(+), 1155 deletions(-) delete mode 100644 doc/fdl.texi create mode 100644 makefile.ed delete mode 100644 mcron.c create mode 100644 mcron.c.template diff --git a/.gitignore b/.gitignore index 0af9e30..2bedd6e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,9 @@ *~ -*.o -*.go .deps INSTALL aclocal.m4 autom4te.cache -/build-aux/compile -/build-aux/config.guess -/build-aux/config.sub -/build-aux/depcomp -/build-aux/install-sh -/build-aux/mdate-sh -/build-aux/missing -/build-aux/texinfo.tex compile -config.cache config.log config.scm config.status @@ -31,6 +20,8 @@ install-sh makefile makefile.in /mcron +mcron.c /mdate-sh +*.o missing texinfo.tex diff --git a/AUTHORS b/AUTHORS index 2e2c046..821f761 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,6 +1,6 @@ Authors of GNU mcron. - Copyright (C) 2003, 2005, 2006, 2015 Dale Mellor + Copyright (C) 2003, 2005, 2006 Dale Mellor Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright @@ -16,6 +16,3 @@ 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. - -Further contributions have been received from Sergey Poznyakoff and Mathieu - Lirzin, and incorporated where appropriate. diff --git a/ChangeLog b/ChangeLog index a458747..7546ceb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,16 +1,3 @@ -2015-10-22 Dale Mellor - - Taken on board suggestions of Mathieu Lirzin. This is mostly - cosmetic code re-arranging and refresh for newer features of - guile, but also: - - * Eliminate the hacked embedding of the main scheme unit into the - C source code. - - * Compile all the guile modules before installation. - - - 2015-07-01 Mathieu Lirzin * configure.ac: Fix package name and bug reports email address. @@ -23,7 +10,7 @@ * .gitignore: Ignore 'mcron' only in the top-level directory. -2014-05-25 Dale Mellor +2014-05-25 Dale Mellor * Juggled build infrastructure so that we can make the minimal man page in the proper autotools way. @@ -31,14 +18,14 @@ * configure.ac: version to 1.0.8. -2014-04-28 Dale Mellor +2014-04-28 Dale Mellor * We now run against, and require, guile-2.0. * configure.ac: version to 1.0.7. -2012-02-04 Dale Mellor +2012-02-04 Dale Mellor * main.scm: added search for initial files in $XDG_CONFIG_HOME/cron directory, defaulting to ~/.config/cron if @@ -47,7 +34,7 @@ standards). -2010-06-13 Dale Mellor +2010-06-13 Dale Mellor * configure.ac: added --enable-no-vixie-clobber argument to configure so that the root user can avoid overwriting a legacy @@ -60,7 +47,7 @@ former is not supplied with the latest automake (1.11). -2008-02-21 Dale Mellor +2008-02-21 Dale Mellor * ALL FILES: Replaced version 2 GPL notices with version 3 ones. @@ -71,7 +58,7 @@ * configure.ac: Bumped version to 1.0.4. -2008-01-25 Dale Mellor +2008-01-25 Dale Mellor * main.scm (command-type): Files which are listed on the command line are assumed to be guile configurations if they do not end in @@ -89,7 +76,7 @@ * Version is currently at 1.0.3. -2005-09-02 Dale Mellor +2005-09-02 Dale Mellor * makefile.am, mcron.c.template (main): Modified install-exec-hook so that a proper installation of a Vixie-compatible cron only @@ -106,7 +93,7 @@ * Bumped version to 1.0.2. -2004-05-15 Dale Mellor +2004-05-15 Dale Mellor * Modified all auxiliary files to reflect that the package is now properly homed at www.gnu.org. @@ -114,7 +101,7 @@ * Bumped version to 1.0.1. -2003-12-11 Dale Mellor +2003-12-11 Dale Mellor * Modified all auxiliary files to reflect that we are now a GNU package. @@ -122,7 +109,7 @@ * Bumped version to 1.0.0. -2003-12-07 Dale Mellor +2003-12-07 Dale Mellor * configure.ac: Added switches for files and directories used by mcron: --spool-dir, --socket-file, --allow-file, --deny-file, @@ -131,14 +118,14 @@ manual). -2003-12-05 Dale Mellor +2003-12-05 Dale Mellor * configure.ac: Added test for guile version >= 1.6.4. * bumped version to 0.99.4. -2003-08-03 Dale Mellor +2003-08-03 Dale Mellor * Third cut, fully functional, modular, production quality, still needs testing... @@ -149,7 +136,7 @@ * Bumped version to 0.99.3. -2003-07-20 Dale Mellor +2003-07-20 Dale Mellor * Second cut, now _really_ fully functional (100% Vixie compatible), production quality code, still needs lots of testing @@ -167,7 +154,7 @@ * Bumped version to 0.99.2. -2003-06-28 Dale Mellor +2003-06-28 Dale Mellor * First cut, fully functional, production quality code, just needs testing... diff --git a/TODO b/TODO index 7572f19..9ed8bca 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,5 @@ GNU mcron --- TODO -*-text-*- - Copyright (C) 2015 Mathieu Lirzin Copyright (C) 2003, 2005, 2006, 2014 Dale Mellor Copying and distribution of this file, with or without modification, @@ -20,14 +19,6 @@ Maybe in the near future... core or other users' files up. Then allow scheme code in the system crontabs. - * Make mcron behavior not depend on the name used to invoke it, to conform - to GNU standards. - - * Provide a test suite using SRFI-64 API. - . - - * Internationalize Mcron using GNU Gettext and ask the Translation - Project to handle the localization. There are no plans to actually do the following any time soon... diff --git a/configure.ac b/configure.ac index 149653d..a3b84e6 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,8 @@ # Process this file with autoconf to produce a configure script. -# Copyright (C) 2003, 2005, 2012, 2014, 2015 Dale Mellor +# Copyright (C) 2003, 2005, 2012, 2014 Dale Mellor +# Copyright (C) 2015 Mathieu Lirzin # # This file is part of GNU mcron. # @@ -23,13 +24,8 @@ AC_PREREQ(2.61) AC_INIT([GNU Mcron], [1.0.8], [bug-mcron@gnu.org]) AC_CONFIG_AUX_DIR([build-aux]) -AM_INIT_AUTOMAKE([silent-rules]) +AM_INIT_AUTOMAKE -# Enable silent rules by default. -AM_SILENT_RULES([yes]) - -guilemoduledir="${datarootdir}/guile/site/2.0" -AC_SUBST([guilemoduledir]) AC_MSG_CHECKING([whether debugging is requested]) AC_ARG_ENABLE(debug, @@ -49,19 +45,12 @@ AC_SUBST(CONFIG_DEBUG) # We have no interest (hence a no-op), but Debian wants this. AC_ARG_ENABLE(maintainer-mode) -AC_CANONICAL_HOST + AC_PROG_AWK AC_PROG_EGREP AM_PROG_CC_C_O -PKG_CHECK_MODULES([GUILE], [guile-2.0 >= 2.0.7]) -AC_PATH_PROG([GUILE], [guile]) - -# search guild -AC_PATH_PROG([GUILD], [guild]) -if test "x$GUILD" = "x"; then - AC_MSG_ERROR(['guild' binary not found; please check your guile-2.x installation.]) -fi +PKG_CHECK_MODULES(GUILE, guile-2.0) # Checks for programs. @@ -75,6 +64,10 @@ AC_CHECK_PROGS(HEAD, head) if test "x$ac_cv_prog_HEAD" = "x"; then AC_MSG_ERROR(head not found) fi +AC_CHECK_PROGS(ED, ed) +if test "x$ac_cv_prog_ED" = "x"; then + AC_MSG_ERROR(ed not found) +fi AC_CHECK_PROGS(WHICH, which) if test "x$ac_cv_prog_WHICH" = "x"; then AC_MSG_ERROR(which not found) diff --git a/doc/fdl.texi b/doc/fdl.texi deleted file mode 100644 index 9c3bbe5..0000000 --- a/doc/fdl.texi +++ /dev/null @@ -1,505 +0,0 @@ -@c The GNU Free Documentation License. -@center Version 1.3, 3 November 2008 - -@c This file is intended to be included within another document, -@c hence no sectioning command or @node. - -@display -Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. -@uref{http://fsf.org/} - -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. -@end display - -@enumerate 0 -@item -PREAMBLE - -The purpose of this License is to make a manual, textbook, or other -functional and useful document @dfn{free} in the sense of freedom: to -assure everyone the effective freedom to copy and redistribute it, -with or without modifying it, either commercially or noncommercially. -Secondarily, this License preserves for the author and publisher a way -to get credit for their work, while not being considered responsible -for modifications made by others. - -This License is a kind of ``copyleft'', which means that derivative -works of the document must themselves be free in the same sense. It -complements the GNU General Public License, which is a copyleft -license designed for free software. - -We have designed this License in order to use it for manuals for free -software, because free software needs free documentation: a free -program should come with manuals providing the same freedoms that the -software does. But this License is not limited to software manuals; -it can be used for any textual work, regardless of subject matter or -whether it is published as a printed book. We recommend this License -principally for works whose purpose is instruction or reference. - -@item -APPLICABILITY AND DEFINITIONS - -This License applies to any manual or other work, in any medium, that -contains a notice placed by the copyright holder saying it can be -distributed under the terms of this License. Such a notice grants a -world-wide, royalty-free license, unlimited in duration, to use that -work under the conditions stated herein. The ``Document'', below, -refers to any such manual or work. Any member of the public is a -licensee, and is addressed as ``you''. You accept the license if you -copy, modify or distribute the work in a way requiring permission -under copyright law. - -A ``Modified Version'' of the Document means any work containing the -Document or a portion of it, either copied verbatim, or with -modifications and/or translated into another language. - -A ``Secondary Section'' is a named appendix or a front-matter section -of the Document that deals exclusively with the relationship of the -publishers or authors of the Document to the Document's overall -subject (or to related matters) and contains nothing that could fall -directly within that overall subject. (Thus, if the Document is in -part a textbook of mathematics, a Secondary Section may not explain -any mathematics.) The relationship could be a matter of historical -connection with the subject or with related matters, or of legal, -commercial, philosophical, ethical or political position regarding -them. - -The ``Invariant Sections'' are certain Secondary Sections whose titles -are designated, as being those of Invariant Sections, in the notice -that says that the Document is released under this License. If a -section does not fit the above definition of Secondary then it is not -allowed to be designated as Invariant. The Document may contain zero -Invariant Sections. If the Document does not identify any Invariant -Sections then there are none. - -The ``Cover Texts'' are certain short passages of text that are listed, -as Front-Cover Texts or Back-Cover Texts, in the notice that says that -the Document is released under this License. A Front-Cover Text may -be at most 5 words, and a Back-Cover Text may be at most 25 words. - -A ``Transparent'' copy of the Document means a machine-readable copy, -represented in a format whose specification is available to the -general public, that is suitable for revising the document -straightforwardly with generic text editors or (for images composed of -pixels) generic paint programs or (for drawings) some widely available -drawing editor, and that is suitable for input to text formatters or -for automatic translation to a variety of formats suitable for input -to text formatters. A copy made in an otherwise Transparent file -format whose markup, or absence of markup, has been arranged to thwart -or discourage subsequent modification by readers is not Transparent. -An image format is not Transparent if used for any substantial amount -of text. A copy that is not ``Transparent'' is called ``Opaque''. - -Examples of suitable formats for Transparent copies include plain -ASCII without markup, Texinfo input format, La@TeX{} input -format, SGML or XML using a publicly available -DTD, and standard-conforming simple HTML, -PostScript or PDF designed for human modification. Examples -of transparent image formats include PNG, XCF and -JPG@. Opaque formats include proprietary formats that can be -read and edited only by proprietary word processors, SGML or -XML for which the DTD and/or processing tools are -not generally available, and the machine-generated HTML, -PostScript or PDF produced by some word processors for -output purposes only. - -The ``Title Page'' means, for a printed book, the title page itself, -plus such following pages as are needed to hold, legibly, the material -this License requires to appear in the title page. For works in -formats which do not have any title page as such, ``Title Page'' means -the text near the most prominent appearance of the work's title, -preceding the beginning of the body of the text. - -The ``publisher'' means any person or entity that distributes copies -of the Document to the public. - -A section ``Entitled XYZ'' means a named subunit of the Document whose -title either is precisely XYZ or contains XYZ in parentheses following -text that translates XYZ in another language. (Here XYZ stands for a -specific section name mentioned below, such as ``Acknowledgements'', -``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title'' -of such a section when you modify the Document means that it remains a -section ``Entitled XYZ'' according to this definition. - -The Document may include Warranty Disclaimers next to the notice which -states that this License applies to the Document. These Warranty -Disclaimers are considered to be included by reference in this -License, but only as regards disclaiming warranties: any other -implication that these Warranty Disclaimers may have is void and has -no effect on the meaning of this License. - -@item -VERBATIM COPYING - -You may copy and distribute the Document in any medium, either -commercially or noncommercially, provided that this License, the -copyright notices, and the license notice saying this License applies -to the Document are reproduced in all copies, and that you add no other -conditions whatsoever to those of this License. You may not use -technical measures to obstruct or control the reading or further -copying of the copies you make or distribute. However, you may accept -compensation in exchange for copies. If you distribute a large enough -number of copies you must also follow the conditions in section 3. - -You may also lend copies, under the same conditions stated above, and -you may publicly display copies. - -@item -COPYING IN QUANTITY - -If you publish printed copies (or copies in media that commonly have -printed covers) of the Document, numbering more than 100, and the -Document's license notice requires Cover Texts, you must enclose the -copies in covers that carry, clearly and legibly, all these Cover -Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on -the back cover. Both covers must also clearly and legibly identify -you as the publisher of these copies. The front cover must present -the full title with all words of the title equally prominent and -visible. You may add other material on the covers in addition. -Copying with changes limited to the covers, as long as they preserve -the title of the Document and satisfy these conditions, can be treated -as verbatim copying in other respects. - -If the required texts for either cover are too voluminous to fit -legibly, you should put the first ones listed (as many as fit -reasonably) on the actual cover, and continue the rest onto adjacent -pages. - -If you publish or distribute Opaque copies of the Document numbering -more than 100, you must either include a machine-readable Transparent -copy along with each Opaque copy, or state in or with each Opaque copy -a computer-network location from which the general network-using -public has access to download using public-standard network protocols -a complete Transparent copy of the Document, free of added material. -If you use the latter option, you must take reasonably prudent steps, -when you begin distribution of Opaque copies in quantity, to ensure -that this Transparent copy will remain thus accessible at the stated -location until at least one year after the last time you distribute an -Opaque copy (directly or through your agents or retailers) of that -edition to the public. - -It is requested, but not required, that you contact the authors of the -Document well before redistributing any large number of copies, to give -them a chance to provide you with an updated version of the Document. - -@item -MODIFICATIONS - -You may copy and distribute a Modified Version of the Document under -the conditions of sections 2 and 3 above, provided that you release -the Modified Version under precisely this License, with the Modified -Version filling the role of the Document, thus licensing distribution -and modification of the Modified Version to whoever possesses a copy -of it. In addition, you must do these things in the Modified Version: - -@enumerate A -@item -Use in the Title Page (and on the covers, if any) a title distinct -from that of the Document, and from those of previous versions -(which should, if there were any, be listed in the History section -of the Document). You may use the same title as a previous version -if the original publisher of that version gives permission. - -@item -List on the Title Page, as authors, one or more persons or entities -responsible for authorship of the modifications in the Modified -Version, together with at least five of the principal authors of the -Document (all of its principal authors, if it has fewer than five), -unless they release you from this requirement. - -@item -State on the Title page the name of the publisher of the -Modified Version, as the publisher. - -@item -Preserve all the copyright notices of the Document. - -@item -Add an appropriate copyright notice for your modifications -adjacent to the other copyright notices. - -@item -Include, immediately after the copyright notices, a license notice -giving the public permission to use the Modified Version under the -terms of this License, in the form shown in the Addendum below. - -@item -Preserve in that license notice the full lists of Invariant Sections -and required Cover Texts given in the Document's license notice. - -@item -Include an unaltered copy of this License. - -@item -Preserve the section Entitled ``History'', Preserve its Title, and add -to it an item stating at least the title, year, new authors, and -publisher of the Modified Version as given on the Title Page. If -there is no section Entitled ``History'' in the Document, create one -stating the title, year, authors, and publisher of the Document as -given on its Title Page, then add an item describing the Modified -Version as stated in the previous sentence. - -@item -Preserve the network location, if any, given in the Document for -public access to a Transparent copy of the Document, and likewise -the network locations given in the Document for previous versions -it was based on. These may be placed in the ``History'' section. -You may omit a network location for a work that was published at -least four years before the Document itself, or if the original -publisher of the version it refers to gives permission. - -@item -For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve -the Title of the section, and preserve in the section all the -substance and tone of each of the contributor acknowledgements and/or -dedications given therein. - -@item -Preserve all the Invariant Sections of the Document, -unaltered in their text and in their titles. Section numbers -or the equivalent are not considered part of the section titles. - -@item -Delete any section Entitled ``Endorsements''. Such a section -may not be included in the Modified Version. - -@item -Do not retitle any existing section to be Entitled ``Endorsements'' or -to conflict in title with any Invariant Section. - -@item -Preserve any Warranty Disclaimers. -@end enumerate - -If the Modified Version includes new front-matter sections or -appendices that qualify as Secondary Sections and contain no material -copied from the Document, you may at your option designate some or all -of these sections as invariant. To do this, add their titles to the -list of Invariant Sections in the Modified Version's license notice. -These titles must be distinct from any other section titles. - -You may add a section Entitled ``Endorsements'', provided it contains -nothing but endorsements of your Modified Version by various -parties---for example, statements of peer review or that the text has -been approved by an organization as the authoritative definition of a -standard. - -You may add a passage of up to five words as a Front-Cover Text, and a -passage of up to 25 words as a Back-Cover Text, to the end of the list -of Cover Texts in the Modified Version. Only one passage of -Front-Cover Text and one of Back-Cover Text may be added by (or -through arrangements made by) any one entity. If the Document already -includes a cover text for the same cover, previously added by you or -by arrangement made by the same entity you are acting on behalf of, -you may not add another; but you may replace the old one, on explicit -permission from the previous publisher that added the old one. - -The author(s) and publisher(s) of the Document do not by this License -give permission to use their names for publicity for or to assert or -imply endorsement of any Modified Version. - -@item -COMBINING DOCUMENTS - -You may combine the Document with other documents released under this -License, under the terms defined in section 4 above for modified -versions, provided that you include in the combination all of the -Invariant Sections of all of the original documents, unmodified, and -list them all as Invariant Sections of your combined work in its -license notice, and that you preserve all their Warranty Disclaimers. - -The combined work need only contain one copy of this License, and -multiple identical Invariant Sections may be replaced with a single -copy. If there are multiple Invariant Sections with the same name but -different contents, make the title of each such section unique by -adding at the end of it, in parentheses, the name of the original -author or publisher of that section if known, or else a unique number. -Make the same adjustment to the section titles in the list of -Invariant Sections in the license notice of the combined work. - -In the combination, you must combine any sections Entitled ``History'' -in the various original documents, forming one section Entitled -``History''; likewise combine any sections Entitled ``Acknowledgements'', -and any sections Entitled ``Dedications''. You must delete all -sections Entitled ``Endorsements.'' - -@item -COLLECTIONS OF DOCUMENTS - -You may make a collection consisting of the Document and other documents -released under this License, and replace the individual copies of this -License in the various documents with a single copy that is included in -the collection, provided that you follow the rules of this License for -verbatim copying of each of the documents in all other respects. - -You may extract a single document from such a collection, and distribute -it individually under this License, provided you insert a copy of this -License into the extracted document, and follow this License in all -other respects regarding verbatim copying of that document. - -@item -AGGREGATION WITH INDEPENDENT WORKS - -A compilation of the Document or its derivatives with other separate -and independent documents or works, in or on a volume of a storage or -distribution medium, is called an ``aggregate'' if the copyright -resulting from the compilation is not used to limit the legal rights -of the compilation's users beyond what the individual works permit. -When the Document is included in an aggregate, this License does not -apply to the other works in the aggregate which are not themselves -derivative works of the Document. - -If the Cover Text requirement of section 3 is applicable to these -copies of the Document, then if the Document is less than one half of -the entire aggregate, the Document's Cover Texts may be placed on -covers that bracket the Document within the aggregate, or the -electronic equivalent of covers if the Document is in electronic form. -Otherwise they must appear on printed covers that bracket the whole -aggregate. - -@item -TRANSLATION - -Translation is considered a kind of modification, so you may -distribute translations of the Document under the terms of section 4. -Replacing Invariant Sections with translations requires special -permission from their copyright holders, but you may include -translations of some or all Invariant Sections in addition to the -original versions of these Invariant Sections. You may include a -translation of this License, and all the license notices in the -Document, and any Warranty Disclaimers, provided that you also include -the original English version of this License and the original versions -of those notices and disclaimers. In case of a disagreement between -the translation and the original version of this License or a notice -or disclaimer, the original version will prevail. - -If a section in the Document is Entitled ``Acknowledgements'', -``Dedications'', or ``History'', the requirement (section 4) to Preserve -its Title (section 1) will typically require changing the actual -title. - -@item -TERMINATION - -You may not copy, modify, sublicense, or distribute the Document -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense, or distribute it is void, and -will automatically terminate your rights under this License. - -However, if you cease all violation of this License, then your license -from a particular copyright holder is reinstated (a) provisionally, -unless and until the copyright holder explicitly and finally -terminates your license, and (b) permanently, if the copyright holder -fails to notify you of the violation by some reasonable means prior to -60 days after the cessation. - -Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - -Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, receipt of a copy of some or all of the same material does -not give you any rights to use it. - -@item -FUTURE REVISIONS OF THIS LICENSE - -The Free Software Foundation may publish new, revised versions -of the GNU Free Documentation License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. See -@uref{http://www.gnu.org/copyleft/}. - -Each version of the License is given a distinguishing version number. -If the Document specifies that a particular numbered version of this -License ``or any later version'' applies to it, you have the option of -following the terms and conditions either of that specified version or -of any later version that has been published (not as a draft) by the -Free Software Foundation. If the Document does not specify a version -number of this License, you may choose any version ever published (not -as a draft) by the Free Software Foundation. If the Document -specifies that a proxy can decide which future versions of this -License can be used, that proxy's public statement of acceptance of a -version permanently authorizes you to choose that version for the -Document. - -@item -RELICENSING - -``Massive Multiauthor Collaboration Site'' (or ``MMC Site'') means any -World Wide Web server that publishes copyrightable works and also -provides prominent facilities for anybody to edit those works. A -public wiki that anybody can edit is an example of such a server. A -``Massive Multiauthor Collaboration'' (or ``MMC'') contained in the -site means any set of copyrightable works thus published on the MMC -site. - -``CC-BY-SA'' means the Creative Commons Attribution-Share Alike 3.0 -license published by Creative Commons Corporation, a not-for-profit -corporation with a principal place of business in San Francisco, -California, as well as future copyleft versions of that license -published by that same organization. - -``Incorporate'' means to publish or republish a Document, in whole or -in part, as part of another Document. - -An MMC is ``eligible for relicensing'' if it is licensed under this -License, and if all works that were first published under this License -somewhere other than this MMC, and subsequently incorporated in whole -or in part into the MMC, (1) had no cover texts or invariant sections, -and (2) were thus incorporated prior to November 1, 2008. - -The operator of an MMC Site may republish an MMC contained in the site -under CC-BY-SA on the same site at any time before August 1, 2009, -provided the MMC is eligible for relicensing. - -@end enumerate - -@page -@heading ADDENDUM: How to use this License for your documents - -To use this License in a document you have written, include a copy of -the License in the document and put the following copyright and -license notices just after the title page: - -@smallexample -@group - Copyright (C) @var{year} @var{your name}. - Permission is granted to copy, distribute and/or modify this document - under the terms of the GNU Free Documentation License, Version 1.3 - or any later version published by the Free Software Foundation; - with no Invariant Sections, no Front-Cover Texts, and no Back-Cover - Texts. A copy of the license is included in the section entitled ``GNU - Free Documentation License''. -@end group -@end smallexample - -If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, -replace the ``with@dots{}Texts.''@: line with this: - -@smallexample -@group - with the Invariant Sections being @var{list their titles}, with - the Front-Cover Texts being @var{list}, and with the Back-Cover Texts - being @var{list}. -@end group -@end smallexample - -If you have Invariant Sections without Cover Texts, or some other -combination of the three, merge those two alternatives to suit the -situation. - -If your document contains nontrivial examples of program code, we -recommend releasing these examples in parallel under your choice of -free software license, such as the GNU General Public License, -to permit their use in free software. - -@c Local Variables: -@c ispell-local-pdict: "ispell-dict" -@c End: diff --git a/doc/mcron.texi b/doc/mcron.texi index 27cd1b7..cb97a06 100644 --- a/doc/mcron.texi +++ b/doc/mcron.texi @@ -63,7 +63,6 @@ running jobs at scheduled times. * Syntax:: All the possibilities for configuring cron jobs. * Invoking:: What happens when you run the mcron command. * Guile modules:: Incorporating mcron into another Guile program. -* GNU Free Documentation License:: The license of this manual. * Index:: The complete index. @detailmenu @@ -1330,11 +1329,6 @@ Once this module has been declared in a program, a crontab file can be used to augment the current job list with a call to @code{read-vixie-file}. -@node GNU Free Documentation License -@appendix GNU Free Documentation License - -@include fdl.texi - @node Index, , Guile modules, Top @unnumbered Index diff --git a/makefile.am b/makefile.am index 0afa5fc..23384bd 100644 --- a/makefile.am +++ b/makefile.am @@ -1,5 +1,6 @@ ## Makefile for the toplevel directory of mcron. -## Copyright (C) 2003, 2015 Dale Mellor +## Copyright (C) 2003 Dale Mellor +## Copyright (C) 2015 Mathieu Lirzin ## # This file is part of GNU mcron. # @@ -16,13 +17,20 @@ # You should have received a copy of the GNU General Public License along # with GNU mcron. If not, see . -## Process this file with automake to produce makefile.in +## Process this file with automake to produce Makefile.in SUBDIRS = scm/mcron . +ED = @ED@ # !!!! Are these needed? CP = @CP@ -EXTRA_DIST = BUGS +MAINTAINERCLEANFILES = configure makefile makefile.in config.guess config.sub \ + install-sh missing texinfo.tex INSTALL \ + aclocal.m4 compile depcomp doc/mcron.1 + +CLEANFILES = mcron.c + +EXTRA_DIST = makefile.ed mcron.c.template BUGS info_TEXINFOS = doc/mcron.texi @@ -34,7 +42,14 @@ mcron_LDADD = @GUILE_LIBS@ # The second option is so that we can execute the binary in the local directory, # in turn so that we can do mcron --help during the build process. -mcron_CFLAGS = @GUILE_CFLAGS@ -DGUILE_LOAD_PATH=\"$(datadir):./scm:...\" +mcron_CFLAGS = @GUILE_CFLAGS@ -DGUILE_LOAD_PATH=\"$(datadir):./scm:...\" + + +mcron.c : scm/mcron/main.scm scm/mcron/crontab.scm makefile.ed mcron.c.template + @echo 'Building mcron.c...' + @$(ED) < makefile.ed > /dev/null 2>&1 + @rm -f mcron.escaped.scm > /dev/null 2>&1 + # Full program prefix. fpp = $(DESTDIR)$(bindir)/@real_program_prefix@ @@ -64,15 +79,11 @@ uninstall-hook: # Not part of formal package building, but a rule for manual use to get the -# elemental man page. -doc/mcron.1 : mcron +# elemental man page. Will only work once the mcron program is installed. +$(dist_man_MANS): mcron.c $(HELP2MAN) -n 'a program to run tasks at regular (or not) intervals' \ - ./mcron > doc/mcron.1 + ./mcron > $@ -MAINTAINERCLEANFILES = configure makefile makefile.in config.guess config.sub \ - install-sh missing texinfo.tex INSTALL \ - aclocal.m4 compile depcomp doc/mcron.1 - maintainer-clean-local: rm -r build-aux diff --git a/makefile.ed b/makefile.ed new file mode 100644 index 0000000..7047ec7 --- /dev/null +++ b/makefile.ed @@ -0,0 +1,34 @@ +# Copyright (C) 2003 Dale Mellor +# +# This file is part of GNU mcron. +# +# GNU mcron is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU mcron is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with GNU mcron. If not, see . +# +# +# +e scm/mcron/main.scm +/\(load "crontab.scm"\)/d +-1r scm/mcron/crontab.scm +%s/\\/\\\\/g +%s/"/\\"/g +%s/ *;;.*$/ /g +g/^ *$/d +%s/^/\"/ +%s/$/\"/ +w mcron.escaped.scm +e mcron.c.template +/GUILE_PROGRAM_GOES_HERE/d +-1r mcron.escaped.scm +w mcron.c +q diff --git a/mcron.c b/mcron.c deleted file mode 100644 index 3776632..0000000 --- a/mcron.c +++ /dev/null @@ -1,115 +0,0 @@ -/* mcron.c -- Run the mcron program. - * - * Copyright (C) 2015 Mathieu Lirzin - * Copyright (C) 2003, 2014 Dale Mellor - * - * This file is part of GNU Mcron. - * - * GNU Mcron is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * GNU Mcron is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with GNU Mcron. If not, see . - */ - - -/* - * This C code represents the thinnest possible wrapper around the Guile code - * which constitutes all the functionality of the mcron program. There are - * two plus one reasons why we need to do this, and one very unfortunate - * consequence. - * - * Firstly, SUID does not work on an executable script. In the end, it is - * the execution of the translator, in our case guile, which determines the - * effective user, and it is not wise to make the system guile installation - * SUID root! - * - * Secondly, executable scripts show up in ugly ways in listings of the - * system process table. Guile in particular, with its multi-line ``#! ...\ - * \n -s ...!#'' idiosyncracies shows up in process listings in a way that - * is difficult to determine what program is actually running. - * - * A third reason for the C wrapper which might be mentioned is that a - * security-conscious system administrator can choose to only install a - * binary, thus removing the possibility of a user studying a guile script - * and working out ways of hacking it to his own ends, or worse still - * finding a way to modify it to his own ends. - * - * Unfortunately, running the guile script from inside a C program means - * that the sigaction function does not work. Instead, it is necessary to - * perform the signal processing in C. - */ - - - -#include -#include -#include -#include - - - -/* Handle the signal and exit. All signals that mcron handles will produce - * the same behavior so we don't need to use the signal value in the - * implementation. */ - -static void -react_to_terminal_signal (int signal) -{ - scm_c_eval_string ("(delete-run-file)"); - exit (1); -} - - - -/* Set up all the signal handlers as required by the cron personality. This - * is necessary to perform the signal processing in C because the sigaction - * function won't work when called from Guile; this function is called from - * the Guile universe. */ - -static SCM -set_cron_signals () -{ - static struct sigaction sa; - - memset (&sa, 0, sizeof (sa)); - sa.sa_handler = react_to_terminal_signal; - sigaction (SIGTERM, &sa, 0); - sigaction (SIGINT, &sa, 0); - sigaction (SIGQUIT, &sa, 0); - sigaction (SIGHUP, &sa, 0); - - return SCM_BOOL_T; -} - - - -/* Launch the Mcron Guile main program. */ - -static void -inner_main (void *closure, int argc, char **argv) -{ - scm_set_current_module (scm_c_resolve_module ("mcron main")); - scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); - scm_c_eval_string ("(main)"); -} - - - -/* The real main function. Does nothing but start up the guile subsystem. */ - -int -main (int argc, char **argv) -{ - setenv ("GUILE_LOAD_PATH", GUILE_LOAD_PATH, 1); - scm_boot_guile (argc, argv, inner_main, 0); - - return 0; -} diff --git a/mcron.c.template b/mcron.c.template new file mode 100644 index 0000000..e9a755d --- /dev/null +++ b/mcron.c.template @@ -0,0 +1,120 @@ +/* -*-c-*- */ +/* + * Copyright (C) 2003, 2014 Dale Mellor + * + * This file is part of GNU mcron. + * + * GNU mcron is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * GNU mcron is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with GNU mcron. If not, see . + */ + + +/* + This C code represents the thinnest possible wrapper around the Guile code + which constitutes all the functionality of the mcron program. There are two + plus one reasons why we need to do this, and one very unfortunate + consequence. + + Firstly, SUID does not work on an executable script. In the end, it is + the execution of the translator, in our case guile, which determines the + effective user, and it is not wise to make the system guile installation + SUID root! + + Secondly, executable scripts show up in ugly ways in listings of the + system process table. Guile in particular, with its multi-line + #! ...\ \n -s ...!# + idiosyncracies shows up in process listings in a way that is difficult + to determine what program is actually running. + + A third reason for the C wrapper which might be mentioned is that a + security-conscious system administrator can choose to only install a + binary, thus removing the possibility of a user studying a guile script + and working out ways of hacking it to his own ends, or worse still + finding a way to modify it to his own ends. + + Unfortunately, running the guile script from inside a C program means + that the sigaction function does not work. Instead, it is necessary to + perform the signal processing in C. + + The guile code itself is substituted for the GU1LE_PROGRAM_GOES_HERE (sic) + token by the makefile, which processes the scheme to make it look like one + big string. +*/ + + + +#include +#include +#include + + + +/* This is a function designed to be installed as a signal handler, for signals + which are supposed to initiate shutdown of this program. It calls the scheme + procedure (see mcron.scm for details) to do all the work, and then exits. */ + +void +react_to_terminal_signal (int sig) +{ + scm_c_eval_string ("(delete-run-file)"); + exit (1); +} + + + +/* This is a function designed to be callable from scheme, and sets up all the + signal handlers required by the cron personality. */ + +SCM +set_cron_signals () +{ + static struct sigaction sa; + memset (&sa, 0, sizeof (sa)); + sa.sa_handler = react_to_terminal_signal; + sigaction (SIGTERM, &sa, 0); + sigaction (SIGINT, &sa, 0); + sigaction (SIGQUIT, &sa, 0); + sigaction (SIGHUP, &sa, 0); + + return SCM_BOOL_T; +} + + + +/* The effective main function (i.e. the one that actually does some work). We + register the function above with the guile system, and then execute the mcron + guile program. */ + +void +inner_main () +{ + scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); + + scm_c_eval_string ( + GUILE_PROGRAM_GOES_HERE + ); +} + + + +/* The real main function. Does nothing but start up the guile subsystem. */ + +int +main (int argc, char **argv) +{ + setenv ("GUILE_LOAD_PATH", GUILE_LOAD_PATH, 1); + + scm_boot_guile (argc, argv, inner_main, 0); + + return 0; +} diff --git a/scm/mcron/config.scm.in b/scm/mcron/config.scm.in index db2bc32..6a0a85d 100644 --- a/scm/mcron/config.scm.in +++ b/scm/mcron/config.scm.in @@ -1,6 +1,5 @@ ;; -*-scheme-*- -;; Copyright (C) 2015 Mathieu Lirzin ;; Copyright (C) 2003 Dale Mellor ;; ;; This file is part of GNU mcron. @@ -24,11 +23,8 @@ (define-module (mcron config)) (define-public config-debug @CONFIG_DEBUG@) -(define-public config-package-name "@PACKAGE_NAME@") -(define-public config-package-version "@PACKAGE_VERSION@") (define-public config-package-string "@PACKAGE_STRING@") (define-public config-package-bugreport "@PACKAGE_BUGREPORT@") -(define-public config-package-url "@PACKAGE_URL@") (define-public config-sendmail "@SENDMAIL@") (define-public config-spool-dir "@CONFIG_SPOOL_DIR@") diff --git a/scm/mcron/crontab.scm b/scm/mcron/crontab.scm index 6be5c61..30e5592 100644 --- a/scm/mcron/crontab.scm +++ b/scm/mcron/crontab.scm @@ -221,8 +221,8 @@ ;; The user is being silly. The message here is identical to the one Vixie cron ;; used to put out, for total compatibility. - (else (mcron-error 15 - "usage error: file name must be specified for replace."))) + (else + (mcron-error 15 "usage error: file name must be specified for replace."))) )) ;; End of file-level let-scopes. diff --git a/scm/mcron/environment.scm b/scm/mcron/environment.scm index f364a38..9f694f1 100644 --- a/scm/mcron/environment.scm +++ b/scm/mcron/environment.scm @@ -1,4 +1,4 @@ -;; Copyright (C) 2003, 2015 Dale Mellor +;; Copyright (C) 2003 Dale Mellor ;; ;; This file is part of GNU mcron. ;; @@ -31,12 +31,42 @@ (define-module (mcron environment) - #:use-module (srfi srfi-26) #:export (modify-environment clear-environment-mods append-environment-mods get-current-environment-mods-copy)) + + + +;; The env-alist is an association list of variable names and values. Variables +;; later in the list will take precedence over variables before. We return a +;; fixed-up version in which some variables are given specific default values +;; (which the user can override), and two variables which the user is not +;; allowed to control are added at the end of the list. + +(define (impose-default-environment env-alist passwd-entry) + (append `(("HOME" . ,(passwd:dir passwd-entry)) + ("CWD" . ,(passwd:dir passwd-entry)) + ("SHELL" . ,(passwd:shell passwd-entry)) + ("TERM" . #f) + ("TERMCAP" . #f)) + env-alist + `(("LOGNAME" . ,(passwd:name passwd-entry)) + ("USER" . ,(passwd:name passwd-entry))))) + + + + +;; Modify the UNIX environment for the current process according to the given +;; association list of variables, with the default variable values imposed. + +(define (modify-environment env-alist passwd-entry) + (for-each (lambda (variable) + (setenv (car variable) (cdr variable))) + (impose-default-environment env-alist passwd-entry))) + + ;; As we parse configuration files, we build up an alist of environment @@ -73,24 +103,3 @@ (set! current-environment-mods (append current-environment-mods (list (cons name value)))) #t) - - - -;; Modify the UNIX environment for the current process according to the given -;; association list of variables, with the default variable values imposed. - -(define (modify-environment env-alist passwd-entry) - (for-each (lambda (a) (setenv (car a) (cdr a))) - (let ((home-dir (passwd:dir passwd-entry)) - (user-name (passwd:name passwd-entry))) - (append - ;; Default environment variables which can be overidden by ENV. - `(("HOME" . ,home-dir) - ("CWD" . ,home-dir) - ("SHELL" . ,(passwd:shell passwd-entry)) - ("TERM" . #f) - ("TERMCAP" . #f)) - env-alist - ;; Environment variables with imposed values. - `(("LOGNAME" . ,user-name) - ("USER" . ,user-name)))))) diff --git a/scm/mcron/job-specifier.scm b/scm/mcron/job-specifier.scm index 7ed912b..cce948c 100644 --- a/scm/mcron/job-specifier.scm +++ b/scm/mcron/job-specifier.scm @@ -34,7 +34,7 @@ set-configuration-time job find-best-next) - #:use-module (mcron mcron-core) + #:use-module (mcron core) #:use-module (mcron environment) #:use-module (mcron vixie-time) #:re-export (append-environment-mods)) @@ -203,16 +203,11 @@ (define configuration-user (getpw (getuid))) (define configuration-time (current-time)) - - (define (set-configuration-user user) (set! configuration-user (if (or (string? user) (integer? user)) (getpw user) user))) - - - (define (set-configuration-time time) (set! configuration-time time)) @@ -238,9 +233,10 @@ ((list? action) (lambda () (primitive-eval action))) ((string? action) (lambda () (system action))) (else - (throw 'mcron-error 2 - "job: invalid second argument (action; should be lambda " - "function, string or list)")))) + (throw 'mcron-error + 2 + "job: invalid second argument (action; should be lambda" + " function, string or list)")))) (time-proc (cond ((procedure? time-proc) time-proc) @@ -248,9 +244,10 @@ ((list? time-proc) (lambda (current-time) (primitive-eval time-proc))) (else - (throw 'mcron-error 3 - "job: invalid first argument (next-time-function; " - "should be function, string or list)")))) + (throw 'mcron-error + 3 + "job: invalid first argument (next-time-function; should ") + "be function, string or list)"))) (displayable (cond ((not (null? displayable)) (car displayable)) ((procedure? action) "Lambda function") diff --git a/scm/mcron/main.scm b/scm/mcron/main.scm index dc839cc..36adef9 100644 --- a/scm/mcron/main.scm +++ b/scm/mcron/main.scm @@ -1,4 +1,4 @@ -;; Copyright (C) 2003, 2012, 2015 Dale Mellor +;; Copyright (C) 2003, 2012 Dale Mellor ;; ;; This file is part of GNU mcron. ;; @@ -16,24 +16,34 @@ ;; with GNU mcron. If not, see . -(define-module (mcron main) - #:use-module (ice-9 getopt-long) - #:use-module (ice-9 rdelim) - #:use-module (ice-9 regex) - #:use-module (mcron config) - #:use-module (mcron mcron-core) - #:use-module (mcron job-specifier) - #:use-module (mcron vixie-specification) - #:use-module (srfi srfi-2) - #:use-module (srfi srfi-26) - #:export (delete-run-file - main)) + +;; This is the 'main' routine for the whole system; the top of this file is the +;; global entry point (after the minimal C wrapper, mcron.c.template); to all +;; intents and purposes the program is pure Guile and starts here. +;; +;; This file is built into mcron.c.template by the makefile, which stringifies +;; the whole lot, and escapes quotation marks and escape characters +;; accordingly. Bear this in mind when considering literal multi-line strings. +;; +;; (l0ad "crontab.scm") (sic) is inlined by the makefile. All other +;; functionality comes through modules in .../share/guile/site/mcron/*.scm. -;; Extract the actual command name from \a command. This returns the last -;; part of \a command without any non-alphabetic characters. For example -;; "in.cron" and "./mcron" will return respectively "cron" and "mcron". +;; Pull in some constants set by the builder (via autoconf) at configuration +;; time. Turn debugging on if indicated. + +(use-modules (mcron config)) +(if config-debug (begin (debug-enable 'debug) + (debug-enable 'backtrace))) + + + +;; To determine the name of the program, scan the first item of the command line +;; backwards for the first non-alphabetic character. This allows names like +;; in.cron to be accepted as an invocation of the cron command. + +(use-modules (ice-9 regex) (ice-9 rdelim)) (define command-name (match:substring (regexp-exec (make-regexp "[[:alpha:]]*$") (car (command-line))))) @@ -41,49 +51,49 @@ ;; Code contributed by Sergey Poznyakoff. Print an error message (made up from -;; the parts of \a rest), and if the \a exit-code error is fatal (present and -;; non-zero) then exit to the system with \a exit-code. +;; the parts of rest), and if the error is fatal (present and non-zero) then +;; exit to the system with this code. (define (mcron-error exit-code . rest) (with-output-to-port (current-error-port) (lambda () - (for-each display - (cons* command-name ": " rest)) + (for-each display (append (list command-name ": ") rest)) (newline))) - (when (and exit-code - (not (eq? exit-code 0))) - (primitive-exit exit-code))) + (if (and exit-code (not (eq? exit-code 0))) + (primitive-exit exit-code))) -;; Code contributed by Sergey Poznyakoff and improved upon by Mathieu Lirzin -;; with newer guile features. Execute the expressions. If an 'mcron-error +;; Code contributed by Sergey Poznyakoff. Execute body. If an 'mcron-error ;; exception occurs, print its diagnostics and exit with its error code. -(define-syntax-rule (catch-mcron-error exp ...) - (catch 'mcron-error - (lambda () exp ...) - (lambda (key exit-code . msg) - (apply mcron-error exit-code msg)))) +(defmacro catch-mcron-error (. body) + `(catch 'mcron-error + (lambda () + ,@body) + (lambda (key exit-code . msg) + (apply mcron-error exit-code msg)))) -;; One of the symbols \c mcron, \c crond or \c crontab according to the means -;; of our invocation. +;; We will be doing a lot of testing of the command name, so it makes sense to +;; perform the string comparisons once and for all here. -(define command-type - (let ((command=? (cute string=? command-name <>))) - (cond ((command=? "mcron") 'mcron) - ((or (command=? "cron") (command=? "crond")) 'cron) - ((command=? "crontab") 'crontab) - (else (mcron-error 12 "The command name is invalid."))))) +(define command-type (cond ((string=? command-name "mcron") 'mcron) + ((or (string=? command-name "cron") + (string=? command-name "crond")) 'cron) + ((string=? command-name "crontab") 'crontab) + (else + (mcron-error 12 "The command name is invalid.")))) -;; There are a different set of options for the crontab personality compared -;; to all the others, with the --help and --version options common to all the +;; There are a different set of options for the crontab personality compared to +;; all the others, with the --help and --version options common to all the ;; personalities. +(use-modules (ice-9 getopt-long)) + (define options (catch 'misc-error @@ -110,86 +120,79 @@ '((version (single-char #\v) (value #f)) (help (single-char #\h) (value #f)))))) (lambda (key func fmt args . rest) - (mcron-error 1 (apply format (cons* #f fmt args)))))) + (mcron-error 1 (apply format (append (list #f fmt) args)))))) + +;; If the user asked for the version of this program, give it to him and get +;; out. + +(if (option-ref options 'version #f) + (begin + (display (string-append "\n +" command-name " (" config-package-string ")\n +Written by Dale Mellor\n +\n +Copyright (C) 2003, 2006, 2014 Dale Mellor\n +This is free software; see the source for copying conditions. There is NO\n +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n +")) + (quit))) -;; Display version information for \a command and quit. +;; Likewise if the user requested the help text. -(define* (show-version #:optional (command command-name)) - (let* ((name config-package-name) - (short-name (cadr (string-split name #\space))) - (version config-package-version)) - (simple-format #t "~a (~a) ~a -Copyright (C) 2015 Free Software Foundation, Inc. +(if (option-ref options 'help #f) + (begin + (display (string-append " +Usage: " (car (command-line)) +(case command-type -License GPLv3+: GNU GPL version 3 or later -This is free software: you are free to change and redistribute it. -There is NO WARRANTY, to the extent permitted by law.\n" - command name version) - (quit))) - - - -;; Display where to get help and send bug reports. - -(define (show-package-information) - (simple-format #t "\nReport bugs to: ~a. -~a home page: <~a> -General help using GNU software: \n" - config-package-bugreport - config-package-name - config-package-url)) - - - -;; Display usage information and quit. - -(define (show-help) - (simple-format #t "Usage: ~a" command-name) - (display - (case command-type - ((mcron) - " [OPTIONS] [FILES] -Run an mcron process according to the specifications in the FILES (`-' for -standard input), or use all the files in ~/.config/cron (or the -deprecated ~/.cron) with .guile or .vixie extensions. - - -v, --version Display version - -h, --help Display this help message - -sN, --schedule[=]N Display the next N jobs that will be run by mcron - -d, --daemon Immediately detach the program from the terminal - and run as a daemon process - -i, --stdin=(guile|vixie) Format of data passed as standard input or + ((mcron) +" [OPTIONS] [FILES]\n +Run an mcron process according to the specifications in the FILES (`-' for\n +standard input), or use all the files in ~/.config/cron (or the \n +deprecated ~/.cron) with .guile or .vixie extensions.\n +\n + -v, --version Display version\n + -h, --help Display this help message\n + -sN, --schedule[=]N Display the next N jobs that will be run by mcron\n + -d, --daemon Immediately detach the program from the terminal\n + and run as a daemon process\n + -i, --stdin=(guile|vixie) Format of data passed as standard input or\n file arguments (default guile)") - ((cron) - " [OPTIONS] -Unless an option is specified, run a cron daemon as a detached process, -reading all the information in the users' crontabs and in /etc/crontab. - -v, --version Display version - -h, --help Display this help message - -sN, --schedule[=]N Display the next N jobs that will be run by cron - -n, --noetc Do not check /etc/crontab for updates (HIGHLY + ((cron) +" [OPTIONS]\n +Unless an option is specified, run a cron daemon as a detached process, \n +reading all the information in the users' crontabs and in /etc/crontab.\n +\n + -v, --version Display version\n + -h, --help Display this help message\n + -sN, --schedule[=]N Display the next N jobs that will be run by cron\n + -n, --noetc Do not check /etc/crontab for updates (HIGHLY\n RECOMMENDED).") - ((crontab) - " [-u user] file - crontab [-u user] { -e | -l | -r } - (default operation is replace, per 1003.2) - -e (edit user's crontab) - -l (list user's crontab) - -r (delete user's crontab)") - (else "\nrubbish"))) - (newline) - (show-package-information) - (quit)) + + ((crontab) + (string-append " [-u user] file\n" + " " (car (command-line)) " [-u user] { -e | -l | -r }\n" + " (default operation is replace, per 1003.2)\n" + " -e (edit user's crontab)\n" + " -l (list user's crontab)\n" + " -r (delete user's crontab)\n")) + + (else "rubbish")) + +"\n\n +Report bugs to " config-package-bugreport ".\n +")) + (quit))) -;; Remove the /var/run/cron.pid file so that crontab and other invocations of -;; cron don't get the wrong idea that a daemon is currently running. This -;; procedure is called from the C front-end whenever a terminal signal is -;; received. +;; This is called from the C front-end whenever a terminal signal is +;; received. We remove the /var/run/cron.pid file so that crontab and other +;; invocations of cron don't get the wrong idea that a daemon is currently +;; running. (define (delete-run-file) (catch #t (lambda () (delete-file config-pid-file) @@ -199,7 +202,47 @@ reading all the information in the users' crontabs and in /etc/crontab. -;; Return standard input as a string. +;; 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. +;; +;; Otherwise, clear the MAILTO environment variable so that output from cron +;; jobs is sent to the various users (this may still be overridden in the +;; configuration files), and call the function in the C wrapper to set up +;; terminal signal responses to vector to the procedure above. The PID file will +;; be filled in properly later when we have forked our daemon process (but not +;; done if we are only viewing the schedules). + +(if (eq? command-type 'cron) + (begin + (if (not (eqv? (getuid) 0)) + (mcron-error 16 + "This program must be run by the root user (and should " + "have been installed as such).")) + (if (access? config-pid-file F_OK) + (mcron-error 1 + "A cron daemon is already running.\n" + " (If you are sure this is not true, remove the file\n" + " " + config-pid-file + ".)")) + (if (not (option-ref options 'schedule #f)) + (with-output-to-file config-pid-file noop)) + (setenv "MAILTO" #f) + (c-set-cron-signals))) + + + +;; Define the functions available to the configuration files. While we're here, +;; we'll get the core loaded as well. + +(use-modules (mcron core) + (mcron job-specifier) + (mcron vixie-specification)) + + + +;; Procedure to slurp the standard input into a string. (define (stdin->string) (with-output-to-string (lambda () (do ((in (read-char) (read-char))) @@ -208,83 +251,183 @@ reading all the information in the users' crontabs and in /etc/crontab. -;; Return a thunk which process each file in \a directory with \a proc. The -;; \a directory must be a directory name. The \a proc argument must be a -;; procedure that takes one file name argument. +;; Now we have the procedures in place for dealing with the contents of +;; configuration files, the crontab personality is able to validate such +;; files. If the user requested the crontab personality, we load and run the +;; code here and then get out. -(define (proc-in-directory directory proc) - (let ((dir (opendir directory))) - (do ((file-name (readdir dir) (readdir dir))) - ((eof-object? file-name) (closedir dir)) - (proc file-name)))) +(if (eq? command-type 'crontab) + (begin + (load "crontab.scm") + (quit))) -;; Process \a file-name according its extension. When \a guile-syntax? is \c -;; TRUE, force guile syntax usage. If \a file-name format is not recognized, -;; it is silently ignored (this deals properly with most editors' backup -;; files, for instance). +;; Code contributed by Sergey Poznyakoff. Determine if the given file is a +;; regular file or not. -(define process-user-file - (let ((guile-regexp (make-regexp "\\.gui(le)?$")) - (vixie-regexp (make-regexp "\\.vix(ie)?$"))) - (lambda* (file-path #:optional assume-guile) - (cond ((string=? "-" file-path) - (if (string=? (option-ref options 'stdin "guile") "vixie") - (read-vixie-port (current-input-port)) - (eval-string (stdin->string)))) - ((regexp-exec vixie-regexp file-path) - (read-vixie-file file-path)) - ((or assume-guile - (regexp-exec guile-regexp file-path)) - (load file-path)))))) +(define (regular-file? file) + (catch 'system-error + (lambda () + (eq? (stat:type (stat file)) 'regular)) + (lambda (key call fmt args . rest) + (mcron-error 0 (apply format (append (list #f fmt) args))) + #f))) -;; Process files in $XDG_CONFIG_HOME/cron and/or ~/.cron directories (if -;; $XDG_CONFIG_HOME is not defined uses ~/.config/cron instead). +;; Procedure which processes any configuration file according to the +;; extension. If a file is not recognized, it is silently ignored (this deals +;; properly with most editors' backup files, for instance). + +(define guile-file-regexp (make-regexp "\\.gui(le)?$")) +(define vixie-file-regexp (make-regexp "\\.vix(ie)?$")) + +(define (process-user-file file-path . assume-guile) + (cond ((string=? file-path "-") + (if (string=? (option-ref options 'stdin "guile") "vixie") + (read-vixie-port (current-input-port)) + (eval-string (stdin->string)))) + ((or (not (null? assume-guile)) + (regexp-exec guile-file-regexp file-path)) + (load file-path)) + ((regexp-exec vixie-file-regexp file-path) + (read-vixie-file file-path)))) + + + +;; Procedure to run through all the files in a user's ~/.cron and/or +;; $XDG_CONFIG_HOME/cron or ~/.config/cron directories (only happens under the +;; mcron personality). (define (process-files-in-user-directory) (let ((errors 0) (home-directory (passwd:dir (getpw (getuid))))) - (map (lambda (dir) - (catch #t - (lambda () - (proc-in-directory - dir - (lambda (file-name) - (process-user-file (string-append dir "/" file-name))))) - (lambda (key . args) - (set! errors (1+ errors))))) - (list (string-append home-directory "/.cron") - (string-append (or (getenv "XDG_CONFIG_HOME") - (string-append home-directory "/.config")) - "/cron"))) - (when (eq? 2 errors) - (mcron-error 13 - "Cannot read files in your ~/.config/cron (or ~/.cron) directory.")))) + (map (lambda (config-directory) + (catch #t + (lambda () + (let ((directory (opendir config-directory))) + (do ((file-name (readdir directory) (readdir directory))) + ((eof-object? file-name) (closedir directory)) + (process-user-file (string-append config-directory + "/" + file-name))))) + (lambda (key . args) + (set! errors (1+ errors))))) + (list (string-append home-directory "/.cron") + (string-append (or (getenv "XDG_CONFIG_HOME") + (string-append home-directory "/.config")) + "/cron"))) + (if (eq? 2 errors) + (mcron-error 13 + "Cannot read files in your ~/.config/cron (or ~/.cron) " + "directory.")))) -;; Process all the files in the crontab directory. When the job procedure is -;; run on behalf of the configuration files, the jobs are registered on the -;; system with the appropriate user. Only root should be able to perform this -;; operation. The permissions on the /var/cron/tabs directory enforce this. +;; 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. + +(define (valid-user user-name) + (setpwent) + (do ((entry (getpw) (getpw))) + ((or (not entry) + (string=? (passwd:name entry) user-name)) + (endpwent) + entry))) + + + +;; Procedure to process all the files in the crontab directory, making sure that +;; each file is for a legitimate user and setting the configuration-user to that +;; user. In this way, when the job procedure is run on behalf of the +;; configuration files, the jobs are registered with the system with the +;; appropriate user. Note that only the root user should be able to perform this +;; operation, but we leave it to the permissions on the /var/cron/tabs directory +;; to enforce this. + +(use-modules (srfi srfi-2)) ;; For and-let*. (define (process-files-in-system-directory) (catch #t - (lambda () - (proc-in-directory - config-spool-dir - (lambda (user-name) - (and-let* ((user (false-if-exception (getpwnam user-name)))) - (set-configuration-user user) - (catch-mcron-error - (read-vixie-file - (string-append config-spool-dir "/" user-name))))))) - (lambda (key . args) - (mcron-error 4 - "You do not have permission to access the system crontabs.")))) + (lambda () + (let ((directory (opendir config-spool-dir))) + (do ((file-name (readdir directory) (readdir directory))) + ((eof-object? file-name)) + (and-let* ((user (valid-user file-name))) + (set-configuration-user user) ;; / ?? !!!! + (catch-mcron-error + (read-vixie-file (string-append config-spool-dir + "/" + file-name))))))) + (lambda (key . args) + (mcron-error + 4 + "You do not have permission to access the system crontabs.")))) + + + +;; 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 +;; passed on the command line, or else all the ones in the user's .config/cron +;; (or .cron) directory. If we are running under the cron personality, we read +;; the /var/cron/tabs directory and also the /etc/crontab file. + +(case command-type + ((mcron) (if (null? (option-ref options '() '())) + (process-files-in-user-directory) + (for-each (lambda (file-path) + (process-user-file file-path #t)) + (option-ref options '() '())))) + + ((cron) (process-files-in-system-directory) + (use-system-job-list) + (catch-mcron-error + (read-vixie-file "/etc/crontab" parse-system-vixie-line)) + (use-user-job-list) + (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 "root") + (job '(- (next-minute-from (next-minute)) 6) + check-system-crontab + "/etc/crontab update checker."))))) + + + +;; If the user has requested a schedule of jobs that will run, we provide the +;; information here and then get out. +;; +;; Start by determining the number of time points in the future that output is +;; required for. This may be provided on the command line as a parameter to the +;; --schedule option, or else we assume a default of 8. Finally, ensure that the +;; count is some positive integer. + +(and-let* ((count (option-ref options 'schedule #f))) + (set! count (string->number count)) + (display (get-schedule (if (<= count 0) 1 count))) + (quit)) + + + +;; If we are supposed to run as a daemon process (either a --daemon option has +;; been explicitly used, or we are running as cron or crond), detach from the +;; terminal now. If we are running as cron, we can now write the PID file. + +(if (option-ref options 'daemon (eq? command-type 'cron)) + (begin + (if (not (eqv? (primitive-fork) 0)) + (quit)) + (setsid) + (if (eq? command-type 'cron) + (with-output-to-file config-pid-file + (lambda () (display (getpid)) (newline)))))) @@ -293,30 +436,32 @@ reading all the information in the users' crontabs and in /etc/crontab. ;; inform the main wait-run-wait execution loop to listen for incoming messages ;; on this socket. -(define (cron-file-descriptors) - (if (eq? command-type 'cron) - (catch #t - (lambda () - (let ((socket (socket AF_UNIX SOCK_STREAM 0))) - (bind socket AF_UNIX config-socket-file) - (listen socket 5) - (list socket))) - (lambda (key . args) - (delete-file config-pid-file) - (mcron-error 1 - "Cannot bind to UNIX socket " config-socket-file))) - '())) +(define fd-list '()) + +(if (eq? command-type 'cron) + (catch #t + (lambda () + (let ((socket (socket AF_UNIX SOCK_STREAM 0))) + (bind socket AF_UNIX config-socket-file) + (listen socket 5) + (set! fd-list (list socket)))) + (lambda (key . args) + (delete-file config-pid-file) + (mcron-error 1 + "Cannot bind to UNIX socket " + config-socket-file)))) + -;; Read a user name from the socket, dealing with the /etc/crontab special +;; This function is called whenever a message comes in on the above socket. We +;; read a user name from the socket, dealing with the "/etc/crontab" special ;; case, remove all the user's jobs from the job list, and then re-read the -;; user's updated file. In the special case drop all the system jobs and -;; re-read the /etc/crontab file. This function should be called whenever a -;; message comes in on the above socket. +;; user's updated file. In the special case we drop all the system jobs and +;; re-read the /etc/crontab file. -(define (process-update-request fd-list) - (let* ((socket (car (accept (car fd-list)))) +(define (process-update-request) + (let* ((socket (car (accept (car fd-list)))) (user-name (read-line socket))) (close socket) (set-configuration-time (current-time)) @@ -330,123 +475,29 @@ reading all the information in the users' crontabs and in /etc/crontab. (let ((user (getpw user-name))) (remove-user-jobs user) (set-configuration-user user) - (read-vixie-file - (string-append config-spool-dir "/" user-name))))))) + (read-vixie-file (string-append config-spool-dir "/" user-name))))))) -;; Entry point. -;; -;; This is the 'main' routine for the whole system; this module is the global -;; entry point (after the minimal C wrapper); to all intents and purposes the -;; program is pure Guile and starts here. -(define (main . args) - ;; Added by Sergey Poznyakoff. This no-op will collect zombie child processes - ;; as soon as they die. This is a big improvement as previously they stayed - ;; around the system until the next time mcron wakes to fire a new job off. - (when config-debug - (debug-enable 'backtrace)) - (when (option-ref options 'version #f) - (show-version)) - (when (option-ref options 'help #f) - (show-help)) - - ;; 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. - ;; - ;; Otherwise, clear the MAILTO environment variable so that output from cron - ;; jobs is sent to the various users (this may still be overridden in the - ;; configuration files), and call the function in the C wrapper to set up - ;; terminal signal responses to vector to the procedure above. The PID file - ;; will be filled in properly later when we have forked our daemon process - ;; (but not done if we are only viewing the schedules). - (when (eq? command-type 'cron) - (unless (eqv? (getuid) 0) - (mcron-error 16 - "This program must be run by the root user (and should have been " - "installed as such).")) - (when (access? config-pid-file F_OK) - (mcron-error 1 - "A cron daemon is already running.\n (If you are sure this is not" - " true, remove the file\n " config-pid-file ".)")) - (unless (option-ref options 'schedule #f) - (with-output-to-file config-pid-file noop)) - (setenv "MAILTO" #f) - ;; Mathieu Lirzin: At compile time, this yields a "possibly unbound - ;; variable" warning, but this is OK since it is bound in the C wrapper. - (c-set-cron-signals)) +;; Added by Sergey Poznyakoff. This no-op will collect zombie child processes +;; as soon as they die. This is a big improvement as previously they stayed +;; around the system until the next time mcron wakes to fire a new job off. - ;; Now we have the procedures in place for dealing with the contents of - ;; configuration files, the crontab personality is able to validate such - ;; files. If the user requested the crontab personality, we load and run the - ;; code here and then get out. - (when (eq? command-type 'crontab) - (load "crontab.scm") - (quit)) +;; Unfortunately it seems to interact badly with the select system call, +;; wreaking havoc... - ;; 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 passed on the command line, or else all the ones in the user's - ;; .config/cron (or .cron) directory. If we are running under the cron - ;; personality, we read the /var/cron/tabs directory and also the - ;; /etc/crontab file. - (case command-type - ((mcron) - (if (null? (option-ref options '() '())) - (process-files-in-user-directory) - (for-each (lambda (file-path) (process-user-file file-path - 'guile-syntax)) - (option-ref options '() '())))) - ((cron) - (process-files-in-system-directory) - (use-system-job-list) - (catch-mcron-error (read-vixie-file "/etc/crontab" - parse-system-vixie-line)) - (use-user-job-list) - (unless (option-ref options 'noetc #f) - (display "\ -WARNING: cron will check for updates to /etc/crontab EVERY MINUTE. If you do -not use this file, or you are prepared to manually restart cron whenever you -make a change, then it is HIGHLY RECOMMENDED that you use the --noetc -option.\n") - (set-configuration-user "root") - (job '(- (next-minute-from (next-minute)) 6) - check-system-crontab - "/etc/crontab update checker.")))) +;; (sigaction SIGCHLD (lambda (sig) noop) SA_RESTART) - ;; If the user has requested a schedule of jobs that will run, we provide - ;; the information here and then get out. Start by determining the number - ;; of time points in the future that output is required for. This may be - ;; provided on the command line as a parameter to the --schedule option, or - ;; else we assume a default of 8. Finally, ensure that the count is some - ;; positive integer. - (and-let* ((count (option-ref options 'schedule #f))) - (set! count (string->number count)) - (display (get-schedule (max 1 count))) - (quit)) - ;; If we are supposed to run as a daemon process (either a --daemon option - ;; has been explicitly used, or we are running as cron or crond), detach - ;; from the terminal now. If we are running as cron, we can now write the - ;; PID file. - (when (option-ref options 'daemon (eq? command-type 'cron)) - (unless (eqv? (primitive-fork) 0) - (quit)) - (setsid) - (when (eq? command-type 'cron) - (with-output-to-file config-pid-file - (lambda () (display (getpid)) (newline))))) - - ;; Now the main loop. Forever execute the run-job-loop procedure in the - ;; mcron core, and when it drops out (can only be because a message has come - ;; in on the socket) we process the socket request before restarting the - ;; loop again. Sergey Poznyakoff: we can also drop out of run-job-loop - ;; because of a SIGCHLD, so must test fd-list. - (catch-mcron-error - (let ((fd-list (cron-file-descriptors))) - (while #t - (run-job-loop fd-list) - (unless (null? fd-list) - (process-update-request fd-list)))))) + +;; Now the main loop. Forever execute the run-job-loop procedure in the mcron +;; core, and when it drops out (can only be because a message has come in on the +;; socket) we process the socket request before restarting the loop again. +;; Sergey Poznyakoff: we can also drop out of run-job-loop because of a SIGCHLD, +;; so must test fd-list. + +(catch-mcron-error + (while #t + (run-job-loop fd-list) + (if (not (null? fd-list)) + (process-update-request)))) diff --git a/scm/mcron/makefile.am b/scm/mcron/makefile.am index e371311..931b03b 100644 --- a/scm/mcron/makefile.am +++ b/scm/mcron/makefile.am @@ -1,60 +1,15 @@ -## Makefile for the scm/mcron directory of mcron. +EXTRA_DIST = main.scm mcron-core.scm vixie-specification.scm \ + crontab.scm environment.scm job-specifier.scm redirect.scm \ + vixie-time.scm -# Copyright (C) 2015 Mathieu Lirzin -# -# This file is part of GNU mcron. -# -# GNU mcron is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later -# version. -# -# GNU mcron is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# GNU mcron. If not, see . - -## Process this file with automake to produce makefile.in. +pkgdata_DATA = core.scm environment.scm job-specifier.scm redirect.scm \ + vixie-time.scm vixie-specification.scm config.scm -MODULES = environment.scm \ - job-specifier.scm \ - main.scm \ - mcron-core.scm \ - redirect.scm \ - vixie-specification.scm \ - vixie-time.scm +# If you're wondering, the configure script keeps deleting all files with a name +# like core.*, so we have to keep re-making it (I lost a good day's work because +# of this). -GOBJECTS = $(MODULES:%.scm=%.go) config.go +core.scm : mcron-core.scm + $(CP) mcron-core.scm core.scm -nobase_dist_guilemodule_DATA = $(MODULES) crontab.scm -nobase_nodist_guilemodule_DATA = $(GOBJECTS) config.scm - -CLEANFILES = $(GOBJECTS) - -AM_V_GUILEC = $(AM_V_GUILEC_$(V)) -AM_V_GUILEC_ = $(AM_V_GUILEC_$(AM_DEFAULT_VERBOSITY)) -AM_V_GUILEC_0 = @echo " GUILEC" $@; - -# Unset 'GUILE_LOAD_COMPILED_PATH' altogether while compiling. Otherwise, if -# $GUILE_LOAD_COMPILED_PATH contains $(moduledir), we may find .go files in -# there that are newer than the local .scm files (for instance because the -# user ran 'make install' recently). When that happens, we end up loading -# those previously-installed .go files, which may be stale, thereby breaking -# the whole thing. -# -# XXX: Use the C locale for when Guile lacks -# . -.scm.go: - $(AM_V_GUILEC)$(MKDIR_P) `dirname "$@"` ; \ - unset GUILE_LOAD_COMPILED_PATH ; \ - LC_ALL=C \ - $(GUILD) compile \ - -L "$(top_builddir)/scm" -L "$(top_srcdir)/scm" \ - -Wformat -Wunbound-variable -Warity-mismatch \ - --target="$(host)" \ - -o "$@" "$<" - -SUFFIXES = .go diff --git a/scm/mcron/mcron-core.scm b/scm/mcron/mcron-core.scm index 9b83faf..518bcac 100644 --- a/scm/mcron/mcron-core.scm +++ b/scm/mcron/mcron-core.scm @@ -1,4 +1,4 @@ -;; Copyright (C) 2003, 2015 Dale Mellor +;; Copyright (C) 2003 Dale Mellor ;; ;; This file is part of GNU mcron. ;; @@ -17,9 +17,8 @@ -(define-module (mcron mcron-core) +(define-module (mcron core) #:use-module (mcron environment) - #:use-module (srfi srfi-9) #:export (add-job remove-user-jobs get-schedule @@ -39,7 +38,7 @@ ;; The list of all jobs known to the system. Each element of the list is ;; -;; (make-job user next-time-function action environment displayable next-time) +;; (vector user next-time-function action environment displayable next-time) ;; ;; where action must be a procedure, and the environment is an alist of ;; modifications that need making to the UNIX environment before the action is @@ -61,17 +60,18 @@ (define (use-system-job-list) (set! configuration-source 'system)) (define (use-user-job-list) (set! configuration-source 'user)) -;; A cron job. -(define-record-type - (make-job user time-proc action environment displayable next-time) - job? - (user job:user) ;string : user passwd entry - (time-proc job:next-time-function) ;proc : with one 'time' parameter - (action job:action) ;thunk : user's code - (environment job:environment) ;alist : environment variables - (displayable job:displayable) ;string : visible in schedule - (next-time job:next-time ;number : time in UNIX format - job:next-time-set!)) + + +;; Convenience functions for getting and setting the elements of a job object. + +(define (job:user job) (vector-ref job 0)) +(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:displayable job) (vector-ref job 4)) +(define (job:next-time job) (vector-ref job 5)) + + ;; Remove jobs from the user-job-list belonging to this user. @@ -97,12 +97,12 @@ (define (add-job time-proc action displayable configuration-time configuration-user) - (let ((entry (make-job configuration-user - time-proc - action - (get-current-environment-mods-copy) - displayable - (time-proc configuration-time)))) + (let ((entry (vector configuration-user + time-proc + action + (get-current-environment-mods-copy) + displayable + (time-proc configuration-time)))) (if (eq? configuration-source 'user) (set! user-job-list (cons entry user-job-list)) (set! system-job-list (cons entry system-job-list))))) @@ -165,17 +165,18 @@ (lambda () (do ((count count (- count 1))) ((eqv? count 0)) - (and-let* - ((next-jobs (find-next-jobs)) - (time (car next-jobs)) - (date-string (strftime "%c %z\n" (localtime time)))) - (for-each (lambda (job) - (display date-string) - (display (job:displayable job)) - (newline)(newline) - (job:next-time-set! job ((job:next-time-function job) - (job:next-time job)))) - (cdr next-jobs))))))) + (and-let* ((next-jobs (find-next-jobs)) + (time (car next-jobs)) + (date-string (strftime "%c %z\n" (localtime time)))) + (for-each (lambda (job) + (display date-string) + (display (job:displayable job)) + (newline)(newline) + (vector-set! job + 5 + ((job:next-time-function job) + (job:next-time job)))) + (cdr next-jobs))))))) @@ -194,21 +195,22 @@ ;; to run. (define (run-jobs jobs-list) - (for-each - (lambda (job) - (if (eqv? (primitive-fork) 0) - (begin - (setgid (passwd:gid (job:user job))) - (setuid (passwd:uid (job:user job))) - (chdir (passwd:dir (job:user job))) - (modify-environment (job:environment job) (job:user job)) - ((job:action job)) - (primitive-exit 0)) - (begin - (set! number-children (+ number-children 1)) - (job:next-time-set! job ((job:next-time-function job) - (current-time)))))) - jobs-list)) + (for-each (lambda (job) + (if (eqv? (primitive-fork) 0) + (begin + (setgid (passwd:gid (job:user job))) + (setuid (passwd:uid (job:user job))) + (chdir (passwd:dir (job:user job))) + (modify-environment (job:environment job) (job:user job)) + ((job:action job)) + (primitive-exit 0)) + (begin + (set! number-children (+ number-children 1)) + (vector-set! job + 5 + ((job:next-time-function job) + (current-time)))))) + jobs-list)) diff --git a/scm/mcron/redirect.scm b/scm/mcron/redirect.scm index af763cb..312b768 100644 --- a/scm/mcron/redirect.scm +++ b/scm/mcron/redirect.scm @@ -31,7 +31,6 @@ (define-module (mcron redirect) #:export (with-mail-out) - #:use-module (ice-9 regex) #:use-module ((mcron config) :select (config-sendmail)) #:use-module (mcron vixie-time)) diff --git a/scm/mcron/vixie-specification.scm b/scm/mcron/vixie-specification.scm index e7fab0a..ab002ba 100644 --- a/scm/mcron/vixie-specification.scm +++ b/scm/mcron/vixie-specification.scm @@ -30,7 +30,7 @@ read-vixie-file check-system-crontab) #:use-module ((mcron config) :select (config-socket-file)) - #:use-module (mcron mcron-core) + #:use-module (mcron core) #:use-module (mcron job-specifier) #:use-module (mcron redirect) #:use-module (mcron vixie-time)) @@ -162,11 +162,13 @@ (parse-vixie-environment line) (parse-vixie-line line))) (lambda (key exit-code . msg) - (throw 'mcron-error exit-code - (apply string-append - (number->string report-line) - ": " - msg))))))))) + (throw + 'mcron-error + exit-code + (apply string-append + (number->string report-line) + ": " + msg))))))))) From de58e99aa569ed936db3e04047f970d6bad10af6 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 27 Sep 2017 23:10:36 +0200 Subject: [PATCH 117/239] Revert "Have a new directory to get rid of with maintainer-clean." This reverts commit 024027ae2dcc425f7a3bf5bf3ff3671833b02ce6. --- ChangeLog | 27 +++++++++++++++++++++++++-- README--git | 20 ++++++++++++++++++++ makefile.am | 6 +----- 3 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 README--git diff --git a/ChangeLog b/ChangeLog index 7546ceb..9675111 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,10 +3,33 @@ * configure.ac: Fix package name and bug reports email address. +2015-06-27 Mathieu Lirzin + + Use a more conventional build system. + * bootstrap: New convenient build script. + * README--git: Document it. + * makefile.am: Capitalize file name. + * makefile.ed: Likewise. + * scm/mcron/makefile: Likewise. + * Makefile.am: New file. + * Makefile.ed: Likewise. + * scm/mcron/Makefile: Likewise. + * .gitignore: Adapt to them. + + 2015-06-26 Mathieu Lirzin - * Fix build of the manual. + Fix build of the manual. + * mcron.texinfo.in: Move to ... + * doc/mcron.texi: ... Here. New file. + * doc/config.texi.in: New file. + * configure.ac: Adapt to it. + * makefile.am: Likewise. + * .gitignore: Likewise. + * README--git: Likewise. + Add missing 'makefile.am'. + * scm/mcron/makefile.am: New file. * .gitignore: Ignore 'mcron' only in the top-level directory. @@ -170,7 +193,7 @@ ________________________________________________________________________________ -Copyright (C) 2003, 2005, 2006, 2014, 2015 Dale Mellor +Copyright (C) 2003, 2005, 2006, 2014 Dale Mellor Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright diff --git a/README--git b/README--git new file mode 100644 index 0000000..9ebaa0d --- /dev/null +++ b/README--git @@ -0,0 +1,20 @@ +GNU mcron --- README--git -*-text-*- + + Copyright (C) 2012, 2014 Dale Mellor + Copyright (C) 2015 Mathieu Lirzin + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. + + +If you have pulled mcron from the GIT repository, these are the steps you will +need to take to build it the first time: + +1) autoreconf -vfi +2) ./configure --prefix={wherever} +3) make install + + +After that it should just be a simple matter of typing `make install' when you +want to build a version with changes in it. diff --git a/makefile.am b/makefile.am index 23384bd..65b10d8 100644 --- a/makefile.am +++ b/makefile.am @@ -51,7 +51,7 @@ mcron.c : scm/mcron/main.scm scm/mcron/crontab.scm makefile.ed mcron.c.template @rm -f mcron.escaped.scm > /dev/null 2>&1 -# Full program prefix. +#full program prefix fpp = $(DESTDIR)$(bindir)/@real_program_prefix@ @@ -83,7 +83,3 @@ uninstall-hook: $(dist_man_MANS): mcron.c $(HELP2MAN) -n 'a program to run tasks at regular (or not) intervals' \ ./mcron > $@ - - -maintainer-clean-local: - rm -r build-aux From 54a0887f1a0a889a4b1afc5ebb30dcddcb2d9b3e Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 27 Sep 2017 23:10:42 +0200 Subject: [PATCH 118/239] Revert "Fix package name and bug reports email address." This reverts commit df4fa60a031e30eff00c2fa06b0ea23d4e50b057. --- ChangeLog | 19 ------------------- configure.ac | 3 +-- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9675111..806a03f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,22 +1,3 @@ -2015-07-01 Mathieu Lirzin - - * configure.ac: Fix package name and bug reports email address. - - -2015-06-27 Mathieu Lirzin - - Use a more conventional build system. - * bootstrap: New convenient build script. - * README--git: Document it. - * makefile.am: Capitalize file name. - * makefile.ed: Likewise. - * scm/mcron/makefile: Likewise. - * Makefile.am: New file. - * Makefile.ed: Likewise. - * scm/mcron/Makefile: Likewise. - * .gitignore: Adapt to them. - - 2015-06-26 Mathieu Lirzin Fix build of the manual. diff --git a/configure.ac b/configure.ac index a3b84e6..b4ec9f6 100644 --- a/configure.ac +++ b/configure.ac @@ -22,8 +22,7 @@ AC_PREREQ(2.61) -AC_INIT([GNU Mcron], [1.0.8], [bug-mcron@gnu.org]) -AC_CONFIG_AUX_DIR([build-aux]) +AC_INIT([mcron], [1.0.8], [dale_mellor@users.sourceforge.net]) AM_INIT_AUTOMAKE From 3eb1889f89a3be70f46df8d0d99d431dc79d59aa Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 27 Sep 2017 23:10:51 +0200 Subject: [PATCH 119/239] Revert "Remove derived doc/mcron.1 with maintainer-clean." This reverts commit eca341bd824c5cfe39fb0001014e5b86933719d9. --- makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile.am b/makefile.am index 65b10d8..2229893 100644 --- a/makefile.am +++ b/makefile.am @@ -26,7 +26,7 @@ CP = @CP@ MAINTAINERCLEANFILES = configure makefile makefile.in config.guess config.sub \ install-sh missing texinfo.tex INSTALL \ - aclocal.m4 compile depcomp doc/mcron.1 + aclocal.m4 compile depcomp mcron.1 CLEANFILES = mcron.c From d96ede0b09dc65903cd5e2231e7c37c2445bedd4 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 27 Sep 2017 23:10:55 +0200 Subject: [PATCH 120/239] Revert "Fix build of the manual." This reverts commit e6a94adeb3384cb883f49ec5a4cc589df6b40d10. --- .gitignore | 9 +-- ChangeLog | 9 --- README--git | 11 ++-- configure.ac | 7 +- doc/config.texi.in | 5 -- makefile.am | 9 ++- doc/mcron.texi => mcron.texinfo.in | 102 ++++++++++++++--------------- 7 files changed, 65 insertions(+), 87 deletions(-) delete mode 100644 doc/config.texi.in rename doc/mcron.texi => mcron.texinfo.in (95%) diff --git a/.gitignore b/.gitignore index 2bedd6e..00fa239 100644 --- a/.gitignore +++ b/.gitignore @@ -10,18 +10,13 @@ config.status configure core.scm depcomp -/doc/.dirstamp -/doc/config.texi -/doc/mcron.info -/doc/mcron.1 -/doc/stamp-vti -/doc/version.texi install-sh makefile makefile.in /mcron mcron.c -/mdate-sh +mcron.info *.o +mcron.texinfo missing texinfo.tex diff --git a/ChangeLog b/ChangeLog index 806a03f..cccecbe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,14 +1,5 @@ 2015-06-26 Mathieu Lirzin - Fix build of the manual. - * mcron.texinfo.in: Move to ... - * doc/mcron.texi: ... Here. New file. - * doc/config.texi.in: New file. - * configure.ac: Adapt to it. - * makefile.am: Likewise. - * .gitignore: Likewise. - * README--git: Likewise. - Add missing 'makefile.am'. * scm/mcron/makefile.am: New file. * .gitignore: Ignore 'mcron' only in the top-level directory. diff --git a/README--git b/README--git index 9ebaa0d..43e9890 100644 --- a/README--git +++ b/README--git @@ -1,7 +1,6 @@ GNU mcron --- README--git -*-text-*- Copyright (C) 2012, 2014 Dale Mellor - Copyright (C) 2015 Mathieu Lirzin Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright @@ -11,9 +10,13 @@ GNU mcron --- README--git -*-text-*- If you have pulled mcron from the GIT repository, these are the steps you will need to take to build it the first time: -1) autoreconf -vfi -2) ./configure --prefix={wherever} -3) make install +1) aclocal +2) autoconf +3) automake -a (will error) +4) ./configure (will error) +5) automake -a +6) ./configure --prefix={wherever} +7) make install After that it should just be a simple matter of typing `make install' when you diff --git a/configure.ac b/configure.ac index b4ec9f6..764ea03 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,6 @@ # Copyright (C) 2003, 2005, 2012, 2014 Dale Mellor -# Copyright (C) 2015 Mathieu Lirzin # # This file is part of GNU mcron. # @@ -175,8 +174,6 @@ AC_SUBST(CONFIG_TMP_DIR) real_program_prefix=`echo $program_prefix | sed s/NONE//` AC_SUBST(real_program_prefix) -AC_CONFIG_FILES([doc/config.texi - makefile - scm/mcron/makefile - scm/mcron/config.scm]) + +AC_CONFIG_FILES(mcron.texinfo makefile scm/mcron/makefile scm/mcron/config.scm) AC_OUTPUT diff --git a/doc/config.texi.in b/doc/config.texi.in deleted file mode 100644 index 50d9a18..0000000 --- a/doc/config.texi.in +++ /dev/null @@ -1,5 +0,0 @@ -@set CONFIG_SOCKET_FILE @CONFIG_SOCKET_FILE@ -@set CONFIG_SPOOL_DIR @CONFIG_SPOOL_DIR@ -@set CONFIG_PID_FILE @CONFIG_PID_FILE@ -@set CONFIG_ALLOW_FILE @CONFIG_ALLOW_FILE@ -@set CONFIG_DENY_FILE @CONFIG_DENY_FILE@ diff --git a/makefile.am b/makefile.am index 2229893..633cf2f 100644 --- a/makefile.am +++ b/makefile.am @@ -1,6 +1,5 @@ ## Makefile for the toplevel directory of mcron. ## Copyright (C) 2003 Dale Mellor -## Copyright (C) 2015 Mathieu Lirzin ## # This file is part of GNU mcron. # @@ -32,9 +31,9 @@ CLEANFILES = mcron.c EXTRA_DIST = makefile.ed mcron.c.template BUGS -info_TEXINFOS = doc/mcron.texi +info_TEXINFOS = mcron.texinfo -dist_man_MANS = doc/mcron.1 +dist_man_MANS = mcron.1 bin_PROGRAMS = mcron mcron_SOURCES = mcron.c @@ -80,6 +79,6 @@ uninstall-hook: # Not part of formal package building, but a rule for manual use to get the # elemental man page. Will only work once the mcron program is installed. -$(dist_man_MANS): mcron.c +mcron.1 : mcron.c $(HELP2MAN) -n 'a program to run tasks at regular (or not) intervals' \ - ./mcron > $@ + ./mcron > mcron.1 diff --git a/doc/mcron.texi b/mcron.texinfo.in similarity index 95% rename from doc/mcron.texi rename to mcron.texinfo.in index cb97a06..bbf8e5b 100644 --- a/doc/mcron.texi +++ b/mcron.texinfo.in @@ -1,14 +1,12 @@ \input texinfo @c %**start of header @setfilename mcron.info -@include config.texi -@include version.texi -@settitle mcron @value{VERSION} +@settitle mcron @VERSION@ @c %**end of header @syncodeindex fn cp -@copying This manual is for GNU mcron (version @value{VERSION}), which is a +@copying This manual is for GNU mcron (version @VERSION@), which is a program for running jobs at scheduled times. Copyright @copyright{} 2003, 2005, 2006, 2012, 2014 Dale Mellor @@ -70,36 +68,36 @@ running jobs at scheduled times. Simple examples -* Guile Simple Examples:: -* Vixie Simple Examples:: +* Guile Simple Examples:: +* Vixie Simple Examples:: Full available syntax -* Guile Syntax:: -* Extended Guile examples:: -* Vixie Syntax:: +* Guile Syntax:: +* Extended Guile examples:: +* Vixie Syntax:: Extended Guile examples -* AT commands:: -* Every second Sunday:: -* Two hours every day:: -* Missing the first appointment:: -* Penultimate day of every month:: +* AT commands:: +* Every second Sunday:: +* Two hours every day:: +* Missing the first appointment:: +* Penultimate day of every month:: Vixie -* Paul Vixie's copyright:: -* Crontab file:: -* Incompatibilities with old Unices:: +* Paul Vixie's copyright:: +* Crontab file:: +* Incompatibilities with old Unices:: Detailed invoking -* Invoking mcron:: -* Invoking cron or crond:: +* Invoking mcron:: +* Invoking cron or crond:: * Invoking crontab:: * Behaviour on laptops:: -* Exit codes:: +* Exit codes:: Guile modules @@ -184,8 +182,8 @@ been to allow such simple specifications to be made easily. The examples show how to create the command descriptions, and subsequently how to run mcron to make them happen. @menu -* Guile Simple Examples:: -* Vixie Simple Examples:: +* Guile Simple Examples:: +* Vixie Simple Examples:: @end menu @node Guile Simple Examples, Vixie Simple Examples, Simple examples, Simple examples @@ -260,9 +258,9 @@ on your system, as root. @node Syntax, Invoking, Simple examples, Top @chapter Full available syntax @menu -* Guile Syntax:: -* Extended Guile examples:: -* Vixie Syntax:: +* Guile Syntax:: +* Extended Guile examples:: +* Vixie Syntax:: @end menu @node Guile Syntax, Extended Guile examples, Syntax, Syntax @section Guile Syntax @@ -394,11 +392,11 @@ they seem. The following examples illustrate some pitfalls, and demonstrate how to code around them. @menu -* AT commands:: -* Every second Sunday:: -* Two hours every day:: -* Missing the first appointment:: -* Penultimate day of every month:: +* AT commands:: +* Every second Sunday:: +* Two hours every day:: +* Missing the first appointment:: +* Penultimate day of every month:: @end menu @node AT commands, Every second Sunday, Extended Guile examples, Extended Guile examples @@ -547,9 +545,9 @@ the variable and runs the command in the user's default shell, as advertised by the /etc/passwd file. @menu -* Paul Vixie's copyright:: -* Crontab file:: -* Incompatibilities with old Unices:: +* Paul Vixie's copyright:: +* Crontab file:: +* Incompatibilities with old Unices:: @end menu @@ -798,11 +796,11 @@ place in the part which implements the mcron personality. @menu -* Invoking mcron:: -* Invoking cron or crond:: +* Invoking mcron:: +* Invoking cron or crond:: * Invoking crontab:: * Behaviour on laptops:: -* Exit codes:: +* Exit codes:: @end menu @node Invoking mcron, Invoking cron or crond, Invoking, Invoking @@ -895,21 +893,21 @@ standard output. @cindex invoking cron @cindex crond, invokation @cindex invoking crond -@cindex @value{CONFIG_SPOOL_DIR} -@cindex @value{CONFIG_SOCKET_FILE} +@cindex @CONFIG_SPOOL_DIR@ +@cindex @CONFIG_SOCKET_FILE@ NOTE THAT THIS SECTION ONLY APPLIES IF THE @code{cron} or @code{crond}, and @code{crontab} PROGRAMS HAVE BEEN INSTALLED BY THE SYSTEM ADMINISTRATOR. If the program runs by the name of @code{cron} or @code{crond}, then -it will read all the files in @code{@value{CONFIG_SPOOL_DIR}} (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 +it will read all the files in @code{@CONFIG_SPOOL_DIR@} (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{@value{CONFIG_SOCKET_FILE}}, 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. +@code{@CONFIG_SOCKET_FILE@}, 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 @@ -1062,7 +1060,7 @@ No problems. @item 1 An attempt has been made to start cron but there is already a -@value{CONFIG_PID_FILE} file. If there really is no other cron daemon +@CONFIG_PID_FILE@ file. If there really is no other cron daemon running (this does not include invokations of mcron) then you should remove this file before attempting to run cron. @@ -1080,9 +1078,9 @@ to be specified in one of these forms. @item 4 An attempt to run cron has been made by a user who does not have -permission to access the crontabs in @value{CONFIG_SPOOL_DIR}. These -files should be readable only by root, and the cron daemon must be run -as root. +permission to access the crontabs in @CONFIG_SPOOL_DIR@. These files +should be readable only by root, and the cron daemon must be run as +root. @item 5 An attempt to run mcron has been made, but there are no jobs to @@ -1090,7 +1088,7 @@ schedule! @item 6 The system administrator has blocked this user from using crontab with -the files @value{CONFIG_ALLOW_FILE} and @value{CONFIG_DENY_FILE}. +the files @CONFIG_ALLOW_FILE@ and @CONFIG_DENY_FILE@. @item 7 Crontab has been run with more than one of the arguments @code{-l}, @@ -1250,7 +1248,7 @@ This module is introduced to a program with the command @code{(use-modules (mcron redirect))}. This module provides the @code{with-mail-out} function, described -fully in @ref{Guile Syntax}. +fully in @ref{Guile Syntax}. @node The vixie-time module, The job-specifier module, The redirect module, Guile modules @section The vixie-time module @@ -1327,7 +1325,7 @@ return silently. Otherwise, the behaviour is identical to Once this module has been declared in a program, a crontab file can be used to augment the current job list with a call to -@code{read-vixie-file}. +@code{read-vixie-file}. @node Index, , Guile modules, Top @unnumbered Index From a0b580448c4b24830ea37190eda53aa84b36cd60 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 27 Sep 2017 23:11:01 +0200 Subject: [PATCH 121/239] Revert "Add missing 'makefile.am'." This reverts commit 2039060a1de3cca3aa3e9a1035ce08b430ff5ea6. --- .gitignore | 2 +- ChangeLog | 7 ------- scm/mcron/makefile.am | 15 --------------- 3 files changed, 1 insertion(+), 23 deletions(-) delete mode 100644 scm/mcron/makefile.am diff --git a/.gitignore b/.gitignore index 00fa239..f8096eb 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,7 @@ depcomp install-sh makefile makefile.in -/mcron +mcron mcron.c mcron.info *.o diff --git a/ChangeLog b/ChangeLog index cccecbe..15e01c0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,10 +1,3 @@ -2015-06-26 Mathieu Lirzin - - Add missing 'makefile.am'. - * scm/mcron/makefile.am: New file. - * .gitignore: Ignore 'mcron' only in the top-level directory. - - 2014-05-25 Dale Mellor * Juggled build infrastructure so that we can make the minimal man diff --git a/scm/mcron/makefile.am b/scm/mcron/makefile.am deleted file mode 100644 index 931b03b..0000000 --- a/scm/mcron/makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -EXTRA_DIST = main.scm mcron-core.scm vixie-specification.scm \ - crontab.scm environment.scm job-specifier.scm redirect.scm \ - vixie-time.scm - -pkgdata_DATA = core.scm environment.scm job-specifier.scm redirect.scm \ - vixie-time.scm vixie-specification.scm config.scm - - -# If you're wondering, the configure script keeps deleting all files with a name -# like core.*, so we have to keep re-making it (I lost a good day's work because -# of this). - -core.scm : mcron-core.scm - $(CP) mcron-core.scm core.scm - From 57b9294277f2f92e1478ff0d478e483d0a584347 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Fri, 13 Jan 2017 17:13:48 +0100 Subject: [PATCH 122/239] wrapper: Avoid 'scm_c_eval_string' usage. * src/wrapper.c (wrap_env_path): New function. (main): Use it. (inner_main): Let 'wrap_env_path' set the environment variables. Don't use 'scm_c_eval_string' when calling 'main' procedure. * Makefile.am (AM_CPPFLAGS): Define _GNU_SOURCE for 'asprintf'. --- Makefile.am | 4 ++-- src/wrapper.c | 50 +++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/Makefile.am b/Makefile.am index 45bb941..a9b2bf7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. # Copyright © 2003 Dale Mellor -# Copyright © 2015, 2016 Mathieu Lirzin +# Copyright © 2015, 2016, 2017 Mathieu Lirzin # # This file is part of GNU Mcron. # @@ -20,7 +20,7 @@ bin_PROGRAMS = bin/mcron bin/crontab sbin_PROGRAMS = bin/cron -AM_CPPFLAGS = -DPACKAGE_LOAD_PATH=\"$(moduledir)\" +AM_CPPFLAGS = -DPACKAGE_LOAD_PATH=\"$(moduledir)\" -D_GNU_SOURCE AM_CFLAGS = @GUILE_CFLAGS@ LDADD = @GUILE_LIBS@ diff --git a/src/wrapper.c b/src/wrapper.c index bb7932e..52bd6ea 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -1,6 +1,6 @@ /* wrapper.c -- C code booting Guile Copyright © 2003, 2014 Dale Mellor - Copyright © 2015, 2016 Mathieu Lirzin + Copyright © 2015, 2016, 2017 Mathieu Lirzin This file is part of GNU Mcron. @@ -23,10 +23,13 @@ #include #include +#include +#include #include #include /* Forward declarations. */ +static void wrap_env_path (const char *envar, const char *dir); static void inner_main (void *closure, int argc, char **argv); static void react_to_terminal_signal (int sig); static SCM set_cron_signals (void); @@ -34,27 +37,52 @@ static SCM set_cron_signals (void); int main (int argc, char **argv) { + /* Set Guile load paths to ensure that Mcron modules will be found after + installation. In a build environment let the 'pre-inst-env' script set + the correct paths. */ + if (getenv ("MCRON_UNINSTALLED") == NULL) + { + wrap_env_path ("GUILE_LOAD_PATH", PACKAGE_LOAD_PATH); + wrap_env_path ("GUILE_LOAD_COMPILED_PATH", PACKAGE_LOAD_PATH); + } + scm_boot_guile (argc, argv, inner_main, 0); return EXIT_SUCCESS; } +/* Append DIR in front of ENVAR environment variable value. If ENVAR is not + defined, then define it with DIR. Bail out if something went wrong. */ +static void +wrap_env_path (const char *envar, const char *dir) +{ + const char *path = getenv (envar); + if (path == NULL) + setenv (envar, dir, true); + else + { + char *new_path; + int ret = asprintf (&new_path, "%s:%s", dir, path); + if (ret >= 0) + setenv (envar, new_path, true); + else + { + perror (envar); + exit (EXIT_FAILURE); + } + free (new_path); + } +} + /* Launch the Mcron Guile main program. */ static void inner_main (void *closure, int argc, char **argv) { - /* Set Guile load paths to ensure that Mcron modules will be found. */ - if (getenv ("MCRON_UNINSTALLED") == NULL) - { - scm_c_eval_string ("(set! %load-path (cons \"" - PACKAGE_LOAD_PATH "\" %load-path))"); - scm_c_eval_string ("(set! %load-compiled-path (cons \"" - PACKAGE_LOAD_PATH "\" %load-compiled-path))"); - } scm_set_current_module (scm_c_resolve_module ("mcron scripts " PROGRAM)); - /* Register set_cron_signals to be called from Guile. */ + /* Register the procedures to be called from Guile. */ scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); - scm_c_eval_string ("(main)"); + /* Call main procedure. */ + scm_call_0 (scm_variable_ref (scm_c_lookup ("main"))); } /* Set up all the signal handlers as required by the cron personality. This From 44e0e6f305e9f579af40915723b1965c565e96b9 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 14 Jan 2017 16:56:37 +0100 Subject: [PATCH 123/239] build: Define PACKAGE_LOAD_COMPILED_PATH macro. * Makefile.am (AM_CPPFLAGS): Define PACKAGE_LOAD_COMPILED_PATH macro. * src/wrapper.c (main): Use it. --- Makefile.am | 6 +++++- src/wrapper.c | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index a9b2bf7..f615857 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,7 +20,11 @@ bin_PROGRAMS = bin/mcron bin/crontab sbin_PROGRAMS = bin/cron -AM_CPPFLAGS = -DPACKAGE_LOAD_PATH=\"$(moduledir)\" -D_GNU_SOURCE +AM_CPPFLAGS = \ + -DPACKAGE_LOAD_PATH=\"$(moduledir)\" \ + -DPACKAGE_LOAD_COMPILED_PATH=\"$(moduledir)\" \ + -D_GNU_SOURCE + AM_CFLAGS = @GUILE_CFLAGS@ LDADD = @GUILE_LIBS@ diff --git a/src/wrapper.c b/src/wrapper.c index 52bd6ea..cef6b3c 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -43,7 +43,7 @@ main (int argc, char **argv) if (getenv ("MCRON_UNINSTALLED") == NULL) { wrap_env_path ("GUILE_LOAD_PATH", PACKAGE_LOAD_PATH); - wrap_env_path ("GUILE_LOAD_COMPILED_PATH", PACKAGE_LOAD_PATH); + wrap_env_path ("GUILE_LOAD_COMPILED_PATH", PACKAGE_LOAD_COMPILED_PATH); } scm_boot_guile (argc, argv, inner_main, 0); From ade37c96b748e5588c148e66e1420b5e4f0e8fd5 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 14 Jan 2017 17:24:25 +0100 Subject: [PATCH 124/239] build: Support Guile 2.2. * configure.ac: Use 'GUILE_PKG' and 'GUILE_PROGS'. Remove explicit Guile version check and check for 'guild'. Honor $GUILE_EFFECTIVE_VERSION in 'moduledir'. --- configure.ac | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 5940555..efb3fe1 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ ## Process this file with autoconf to produce a configure script. # Copyright © 2003, 2005, 2012, 2014 Dale Mellor # -# Copyright © 2015, 2016 Mathieu Lirzin +# Copyright © 2015, 2016, 2017 Mathieu Lirzin # # This file is part of GNU Mcron. # @@ -29,9 +29,6 @@ AC_REQUIRE_AUX_FILE([git-version-gen]) AM_INIT_AUTOMAKE([subdir-objects -Wall -Wno-override]) AM_SILENT_RULES([yes]) # enables silent rules by default -moduledir="${datarootdir}/guile/site/2.0" -AC_SUBST([moduledir]) -AC_SUBST([mcronmoduledir], ["${moduledir}/mcron"]) AC_MSG_CHECKING([whether debugging is requested]) AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], @@ -55,16 +52,22 @@ AC_PROG_AWK AC_PROG_EGREP AM_PROG_CC_C_O -PKG_CHECK_MODULES([GUILE], [guile-2.0 >= 2.0.7]) -AC_PATH_PROG([GUILE], [guile]) +# Check for Guile 2.x. development files +GUILE_PKG([2.2 2.0]) -# search guild -AC_PATH_PROG([GUILD], [guild]) -AS_IF([test -z "$ac_cv_path_GUILD"], - [AC_MSG_ERROR(['guild' program cannot be found.])]) +# Set directories for installed Guile modules +moduledir="${datarootdir}/guile/site/$GUILE_EFFECTIVE_VERSION" +AC_SUBST([moduledir]) +AC_SUBST([mcronmoduledir], ["${moduledir}/mcron"]) + +# Set Guile flags without using GUILE_FLAGS which is requiring the unused +# 'config.rpath' script. +PKG_CHECK_MODULES(GUILE, [guile-$GUILE_EFFECTIVE_VERSION]) # Checks for programs. - + +GUILE_PROGS + AM_MISSING_PROG(HELP2MAN, help2man, $missing_dir) AC_CHECK_PROGS(SED, sed) From c2cdfefaca4ff87a458487257a9b20d911a969df Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 14 Jan 2017 17:51:58 +0100 Subject: [PATCH 125/239] build: Rename variables for Guile install directories. * configure.ac (moduledir, mcronmoduledir): Rename to ... * Makefile.am (guilesitedir, pkgmoduledir): ... these. (dist_mcronmodule_DATA, mcronmodule_DATA, mcronscriptdir) (dist_mcronscript_DATA, mcronscript_DATA): Rename to ... (dist_pkgmodule_DATA, pkgmodule_DATA, pkgscriptdir, dist_pkgscript_DATA) (pkgscript_DATA): ... these. (modules): Adapt. --- Makefile.am | 22 +++++++++++++--------- configure.ac | 5 ----- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Makefile.am b/Makefile.am index f615857..f73f23e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -40,7 +40,11 @@ bin_crontab_SOURCES = src/wrapper.c bin_crontab_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"crontab\"" bin_crontab_DEPENDENCIES = $(modules:.scm=.go) -dist_mcronmodule_DATA = \ +# Root directory used for installing Guile modules. +guilesitedir = $(datarootdir)/guile/site/$(GUILE_EFFECTIVE_VERSION) + +pkgmoduledir = $(guilesitedir)/$(PACKAGE) +dist_pkgmodule_DATA = \ src/mcron/base.scm \ src/mcron/environment.scm \ src/mcron/job-specifier.scm \ @@ -49,22 +53,22 @@ dist_mcronmodule_DATA = \ src/mcron/vixie-specification.scm \ src/mcron/vixie-time.scm -mcronmodule_DATA = \ - $(dist_mcronmodule_DATA:.scm=.go) \ +pkgmodule_DATA = \ + $(dist_pkgmodule_DATA:.scm=.go) \ src/mcron/config.scm \ src/mcron/config.go -mcronscriptdir = $(mcronmoduledir)/scripts -dist_mcronscript_DATA = \ +pkgscriptdir = $(pkgmoduledir)/scripts +dist_pkgscript_DATA = \ src/mcron/scripts/cron.scm \ src/mcron/scripts/crontab.scm \ src/mcron/scripts/mcron.scm -mcronscript_DATA = $(dist_mcronscript_DATA:.scm=.go) +pkgscript_DATA = $(dist_pkgscript_DATA:.scm=.go) modules = \ - $(dist_mcronmodule_DATA) \ - $(dist_mcronscript_DATA) \ + $(dist_pkgmodule_DATA) \ + $(dist_pkgscript_DATA) \ src/mcron/config.scm TEST_EXTENSIONS = .scm @@ -79,7 +83,7 @@ TESTS = \ tests/job-specifier.scm # Unset 'GUILE_LOAD_COMPILED_PATH' altogether while compiling. Otherwise, if -# $GUILE_LOAD_COMPILED_PATH contains $(mcronmoduledir), we may find .go files +# $GUILE_LOAD_COMPILED_PATH contains $(pkgmoduledir), we may find .go files # in there that are newer than the local .scm files (for instance because the # user ran 'make install' recently). When that happens, we end up loading # those previously-installed .go files, which may be stale, thereby breaking diff --git a/configure.ac b/configure.ac index efb3fe1..8c5fc08 100644 --- a/configure.ac +++ b/configure.ac @@ -55,11 +55,6 @@ AM_PROG_CC_C_O # Check for Guile 2.x. development files GUILE_PKG([2.2 2.0]) -# Set directories for installed Guile modules -moduledir="${datarootdir}/guile/site/$GUILE_EFFECTIVE_VERSION" -AC_SUBST([moduledir]) -AC_SUBST([mcronmoduledir], ["${moduledir}/mcron"]) - # Set Guile flags without using GUILE_FLAGS which is requiring the unused # 'config.rpath' script. PKG_CHECK_MODULES(GUILE, [guile-$GUILE_EFFECTIVE_VERSION]) From 3b5195ed3370bd945903e26d69d3fa37d4ace75e Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 14 Jan 2017 18:07:15 +0100 Subject: [PATCH 126/239] build: Don't generate '.version' file. * Makefile.am (.version): Remove target which has no use. (EXTRA_DIST): Adapt. (BUILT_SOURCES): Delete. * .gitignore: Update. --- .gitignore | 1 - Makefile.am | 5 ----- 2 files changed, 6 deletions(-) diff --git a/.gitignore b/.gitignore index 44aed99..e9633aa 100644 --- a/.gitignore +++ b/.gitignore @@ -24,7 +24,6 @@ /doc/stamp-vti /doc/version.texi /mdate-sh -/.version INSTALL Makefile Makefile.in diff --git a/Makefile.am b/Makefile.am index f73f23e..d1b8fbd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -105,10 +105,6 @@ TESTS = \ SUFFIXES = .go noinst_SCRIPTS = pre-inst-env -BUILT_SOURCES= .version -.version: - $(AM_V_GEN)echo $(VERSION) > $@-t && mv $@-t $@ - dist-hook: gen-ChangeLog $(AM_V_GEN)echo $(VERSION) > $(distdir)/.tarball-version @@ -152,7 +148,6 @@ uninstall-hook: EXTRA_DIST = \ build-aux/guix.scm \ - .version \ $(TESTS) MAINTAINERCLEANFILES = $(dist_man_MANS) From f1c498c2dddd4969d7ad3725dede9686273f70b2 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 14 Jan 2017 18:38:23 +0100 Subject: [PATCH 127/239] build: Install '.go' files under LIBDIR. * Makefile.am (compiled_modules): New variable. (bin_mcron_DEPENDENCIES, bin_cron_DEPENDENCIES) (bin_crontab_DEPENDENCIES): Use it. (guilesitegodir, pkgmodulegodir, pkgmodulego_DATA) (pkgscriptgodir, pkgscriptgo_DATA): New variables (pkgmodule_DATA): Remove compiled modules. (pkgscript_DATA): Delete. (DISTCLEANFILES, CLEANFILES): Update. --- Makefile.am | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/Makefile.am b/Makefile.am index d1b8fbd..ed0f310 100644 --- a/Makefile.am +++ b/Makefile.am @@ -30,20 +30,23 @@ LDADD = @GUILE_LIBS@ bin_mcron_SOURCES = src/wrapper.c bin_mcron_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"mcron\"" -bin_mcron_DEPENDENCIES = $(modules:.scm=.go) +bin_mcron_DEPENDENCIES = $(compiled_modules) bin_cron_SOURCES = src/wrapper.c bin_cron_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"cron\"" -bin_cron_DEPENDENCIES = $(modules:.scm=.go) +bin_cron_DEPENDENCIES = $(compiled_modules) bin_crontab_SOURCES = src/wrapper.c bin_crontab_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"crontab\"" -bin_crontab_DEPENDENCIES = $(modules:.scm=.go) +bin_crontab_DEPENDENCIES = $(compiled_modules) # Root directory used for installing Guile modules. guilesitedir = $(datarootdir)/guile/site/$(GUILE_EFFECTIVE_VERSION) +# Root directory used for installing Guile compiled modules. +guilesitegodir = $(libdir)/guile/$(GUILE_EFFECTIVE_VERSION)/site-ccache pkgmoduledir = $(guilesitedir)/$(PACKAGE) +pkgmodule_DATA = src/mcron/config.scm dist_pkgmodule_DATA = \ src/mcron/base.scm \ src/mcron/environment.scm \ @@ -53,9 +56,9 @@ dist_pkgmodule_DATA = \ src/mcron/vixie-specification.scm \ src/mcron/vixie-time.scm -pkgmodule_DATA = \ +pkgmodulegodir = $(guilesitegodir)/$(PACKAGE) +pkgmodulego_DATA = \ $(dist_pkgmodule_DATA:.scm=.go) \ - src/mcron/config.scm \ src/mcron/config.go pkgscriptdir = $(pkgmoduledir)/scripts @@ -64,12 +67,12 @@ dist_pkgscript_DATA = \ src/mcron/scripts/crontab.scm \ src/mcron/scripts/mcron.scm -pkgscript_DATA = $(dist_pkgscript_DATA:.scm=.go) +pkgscriptgodir = $(pkgmodulegodir)/scripts +pkgscriptgo_DATA = $(dist_pkgscript_DATA:.scm=.go) -modules = \ - $(dist_pkgmodule_DATA) \ - $(dist_pkgscript_DATA) \ - src/mcron/config.scm +compiled_modules = \ + $(pkgmodulego_DATA) \ + $(pkgscriptgo_DATA) TEST_EXTENSIONS = .scm AM_TESTS_ENVIRONMENT = env GUILE_AUTO_COMPILE='0' @@ -151,10 +154,8 @@ EXTRA_DIST = \ $(TESTS) MAINTAINERCLEANFILES = $(dist_man_MANS) -DISTCLEANFILES = src/config.scm -CLEANFILES = \ - $(modules:.scm=.go) \ - src/mcron/config.go +DISTCLEANFILES = src/mcron/config.scm +CLEANFILES = $(compiled_modules) ## --------------- ## ## Documentation. ## From 10df45c659b742732bf71dc9cbee5a8286567e5d Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 14 Jan 2017 20:00:38 +0100 Subject: [PATCH 128/239] job-specifier: Remove dependency on SRFI-26. * src/mcron/job-specifier.scm (range): Use plain lambda instead of 'cut' and 'cute'. --- src/mcron/job-specifier.scm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/mcron/job-specifier.scm b/src/mcron/job-specifier.scm index d4c05bd..30c770a 100644 --- a/src/mcron/job-specifier.scm +++ b/src/mcron/job-specifier.scm @@ -1,6 +1,6 @@ ;;;; job-specifier.scm -- public interface for defining jobs ;;; Copyright © 2003 Dale Mellor -;;; Copyright © 2016 Mathieu Lirzin +;;; Copyright © 2016, 2017 Mathieu Lirzin ;;; ;;; This file is part of GNU Mcron. ;;; @@ -32,7 +32,6 @@ #:use-module (mcron environment) #:use-module (mcron vixie-time) #:use-module (srfi srfi-1) - #:use-module (srfi srfi-26) #:re-export (append-environment-mods) #:export (range next-year-from next-year @@ -49,7 +48,11 @@ "Produces a list of values from START up to (but not including) END. An optional STEP may be supplied, and (if positive) only every step'th value will go into the list. For example, (range 1 6 2) returns '(1 3 5)." - (unfold (cut >= <> end) identity (cute + <> (max step 1)) start)) + (let ((step* (max step 1))) + (unfold (λ (i) (>= i end)) ;predicate + identity ;value + (λ (i) (+ step* i)) ;next seed + start))) ;seed (define (%find-best-next current next-list) ;; Takes a value and a list of possible next values. It returns a pair From ec5ece53d6fe13fee7a673a05256458331132350 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 15 Jan 2017 22:48:02 +0100 Subject: [PATCH 129/239] base: Add 'run-job' procedure. * src/mcron/base.scm (run-jobs): Delete. (run-job): New procedure. (run-job-loop): Use it. --- src/mcron/base.scm | 51 ++++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/src/mcron/base.scm b/src/mcron/base.scm index c100b4f..942ebf2 100644 --- a/src/mcron/base.scm +++ b/src/mcron/base.scm @@ -171,36 +171,25 @@ recurse the list." (define number-children 0) - - -;; For every job on the list, fork a process to run it (noting the fact by -;; increasing the number-children counter), and in the new process set up the -;; run-time environment exactly as it should be before running the job proper. -;; -;; In the parent, update the job entry by computing the next time the job needs -;; to run. - -(define (run-jobs jobs-list) - (for-each - (lambda (job) - (if (eqv? (primitive-fork) 0) - (dynamic-wind - (const #t) - (lambda () - (setgid (passwd:gid (job:user job))) - (setuid (passwd:uid (job:user job))) - (chdir (passwd:dir (job:user job))) - (modify-environment (job:environment job) (job:user job)) - ((job:action job))) - (lambda () - (primitive-exit 0))) - (begin - (set! number-children (+ number-children 1)) - (job:next-time-set! job ((job:next-time-function job) - (current-time)))))) - jobs-list)) - - +(define (run-job job) + "Run JOB in a separate process. The process is run as JOB user with the +environment properly set. Update the NEXT-TIME field of JOB by computing its +next value." + (if (= (primitive-fork) 0) + (dynamic-wind ;child + (const #t) + (λ () + (setgid (passwd:gid (job:user job))) + (setuid (passwd:uid (job:user job))) + (chdir (passwd:dir (job:user job))) + (modify-environment (job:environment job) (job:user job)) + ((job:action job))) + (λ () + (primitive-exit 0))) + (begin ;parent + (set! number-children (+ number-children 1)) + (job:next-time-set! job ((job:next-time-function job) + (current-time)))))) ;; Give any zombie children a chance to die, and decrease the number known to ;; exist. @@ -242,6 +231,6 @@ recurse the list." (else (apply throw key args))))))))) (break)) - (run-jobs next-jobs-lst) + (for-each run-job next-jobs-lst) (child-cleanup) (loop)))))))) From ab07cf296b29f65afebb2186b4f02d725d35502f Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 18 Feb 2017 23:44:31 +0100 Subject: [PATCH 130/239] Add (mcron core) module. This module is an alias for (mcron base) module. This modules is added to keep backward compatibility with Mcron 1.x. --- Makefile.am | 3 +++ src/mcron/core.scm | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/mcron/core.scm diff --git a/Makefile.am b/Makefile.am index ed0f310..808267e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,6 +56,9 @@ dist_pkgmodule_DATA = \ src/mcron/vixie-specification.scm \ src/mcron/vixie-time.scm +# Alias for 'src/mcron/base.scm' kept for backward compatibility. +dist_pkgmodule_DATA += src/mcron/core.scm + pkgmodulegodir = $(guilesitegodir)/$(PACKAGE) pkgmodulego_DATA = \ $(dist_pkgmodule_DATA:.scm=.go) \ diff --git a/src/mcron/core.scm b/src/mcron/core.scm new file mode 100644 index 0000000..fcf96af --- /dev/null +++ b/src/mcron/core.scm @@ -0,0 +1,32 @@ +;;;; core.scm -- alias for (mcron base) kept for backward compatibility +;;; Copyright © 2017 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . + +;;; TODO: Deprecate this alias in next major version. + +(define-module (mcron core) + #:use-module (mcron base) + #:re-export (add-job + remove-user-jobs + get-schedule + run-job-loop + clear-environment-mods + append-environment-mods + ;; Deprecated and undocumented procedures. + use-system-job-list + use-user-job-list + clear-system-jobs)) From a0a82a2ef4a69b911118fd62d9d0d27cfbaadfa0 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 18 Feb 2017 23:59:09 +0100 Subject: [PATCH 131/239] build: Add 'bootstrap' script. * bootstrap: New file. * Makefile.am (EXTRA_DIST): Add it. --- Makefile.am | 1 + bootstrap | 5 +++++ 2 files changed, 6 insertions(+) create mode 100755 bootstrap diff --git a/Makefile.am b/Makefile.am index 808267e..e513b2b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -153,6 +153,7 @@ uninstall-hook: fi EXTRA_DIST = \ + bootstrap \ build-aux/guix.scm \ $(TESTS) diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..8d2758f --- /dev/null +++ b/bootstrap @@ -0,0 +1,5 @@ +#!/bin/sh +# Initialize the build system. + +set -e -x +exec autoreconf -vfi From f284b524465afcac4ff248ae5aecfefa7348d05f Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 22 Feb 2017 15:20:25 +0100 Subject: [PATCH 132/239] build: Separate "Makefile.am" into more sections. * Makefile.am: Add "Installation", "Distribution", "Test suite", "Programs", and "Guile modules" sections. --- Makefile.am | 78 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 28 deletions(-) diff --git a/Makefile.am b/Makefile.am index e513b2b..ce3ad57 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,6 +17,10 @@ # You should have received a copy of the GNU General Public License # along with GNU Mcron. If not, see . +## ---------- ## +## Programs. ## +## ---------- ## + bin_PROGRAMS = bin/mcron bin/crontab sbin_PROGRAMS = bin/cron @@ -40,6 +44,13 @@ bin_crontab_SOURCES = src/wrapper.c bin_crontab_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"crontab\"" bin_crontab_DEPENDENCIES = $(compiled_modules) +# wrapper to be used in the build environment and for running tests. +noinst_SCRIPTS = pre-inst-env + +## --------------- ## +## Guile modules. ## +## --------------- ## + # Root directory used for installing Guile modules. guilesitedir = $(datarootdir)/guile/site/$(GUILE_EFFECTIVE_VERSION) # Root directory used for installing Guile compiled modules. @@ -77,16 +88,8 @@ compiled_modules = \ $(pkgmodulego_DATA) \ $(pkgscriptgo_DATA) -TEST_EXTENSIONS = .scm -AM_TESTS_ENVIRONMENT = env GUILE_AUTO_COMPILE='0' - -SCM_LOG_DRIVER = \ - $(builddir)/pre-inst-env $(GUILE) \ - $(srcdir)/build-aux/test-driver.scm - -TESTS = \ - tests/environment.scm \ - tests/job-specifier.scm +CLEANFILES = $(compiled_modules) +DISTCLEANFILES = src/mcron/config.scm # Unset 'GUILE_LOAD_COMPILED_PATH' altogether while compiling. Otherwise, if # $GUILE_LOAD_COMPILED_PATH contains $(pkgmoduledir), we may find .go files @@ -99,21 +102,38 @@ TESTS = \ # XXX: Use the C locale for when Guile lacks # . .scm.go: - $(guilec_verbose)$(MKDIR_P) `dirname "$@"` ; \ - export GUILE_AUTO_COMPILE=0 ; unset GUILE_LOAD_COMPILED_PATH ; \ - LC_ALL=C \ - $(top_builddir)/pre-inst-env $(GUILD) compile \ - --load-path="$(top_builddir)/src" \ - --load-path="$(top_srcdir)/src" \ - --warn=format --warn=unbound-variable --warn=arity-mismatch \ + $(guilec_verbose)$(MKDIR_P) `dirname "$@"`; \ + export GUILE_AUTO_COMPILE=0; unset GUILE_LOAD_COMPILED_PATH; \ + LC_ALL=C \ + $(top_builddir)/pre-inst-env $(GUILD) compile \ + --load-path="$(builddir)/src" \ + --load-path="$(srcdir)/src" \ + --warn=format --warn=unbound-variable --warn=arity-mismatch \ --target="$(host)" --output="$@" "$<" $(devnull_verbose) -SUFFIXES = .go -noinst_SCRIPTS = pre-inst-env +## ------------ ## +## Test suite. ## +## ------------ ## + +TEST_EXTENSIONS = .scm +AM_TESTS_ENVIRONMENT = env GUILE_AUTO_COMPILE='0' + +SCM_LOG_DRIVER = \ + $(builddir)/pre-inst-env $(GUILE) \ + $(srcdir)/build-aux/test-driver.scm + +TESTS = \ + tests/environment.scm \ + tests/job-specifier.scm + +## -------------- ## +## Distribution. ## +## -------------- ## dist-hook: gen-ChangeLog $(AM_V_GEN)echo $(VERSION) > $(distdir)/.tarball-version +# Generate the ChangeLog file from Git commit logs. gen_start_date = 2015-06-26 .PHONY: gen-ChangeLog gen-ChangeLog: @@ -128,6 +148,15 @@ gen-ChangeLog: mv $(distdir)/cl-t $(distdir)/ChangeLog; } \ fi +EXTRA_DIST = \ + bootstrap \ + build-aux/guix.scm \ + $(TESTS) + +## -------------- ## +## Installation. ## +## -------------- ## + #full program prefix fpp = $(DESTDIR)$(bindir)/@real_program_prefix@ @@ -152,15 +181,6 @@ uninstall-hook: rm -f $(fpp){cron,crontab}$(EXEEXT); \ fi -EXTRA_DIST = \ - bootstrap \ - build-aux/guix.scm \ - $(TESTS) - -MAINTAINERCLEANFILES = $(dist_man_MANS) -DISTCLEANFILES = src/mcron/config.scm -CLEANFILES = $(compiled_modules) - ## --------------- ## ## Documentation. ## ## --------------- ## @@ -198,6 +218,8 @@ $(srcdir)/doc/crontab.1: src/mcron/scripts/crontab.scm bin/crontab $(srcdir)/doc/cron.8: src/mcron/scripts/cron.scm bin/cron -@prog="cron"; man_section=8; $(gen_man) +MAINTAINERCLEANFILES = $(dist_man_MANS) + ## -------------- ## ## Silent rules. ## ## -------------- ## From 245f1ae3380330e31bfdcb7f4fe17698a2fa021d Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 22 Feb 2017 15:49:18 +0100 Subject: [PATCH 133/239] build: Replace "--enable-no-vixie-clobber" with "--disable-multi-user". * configure.ac: Define "--disable-multi-user" option instead of "--enable-no-vixie-clobber". * Makefile.am (install-exec-hook) [MULTI_USER]: Only set crontab setuid bit. (bin_PROGRAMS): Keep only 'mcron' by default. (bin_PROGRAMS) [MULTI_USER]: Add 'crontab' (sbin_PROGRAMS) [MULTI_USER]: Add 'cron'. (noinst_PROGRAMS) [!MULTI_USER]: Add 'cron' and 'crontab'. (dist_man_MANS): Move 'crontab.1' and 'cron.8' ... (extra_mans): here. New variable. (dist_man_MANS) [MULTI_USER]: Add it. (all-local) [!MULTI_USER]: New target. Depend on it. (EXTRA_DIST) [!MULTI_USER]: Distribute it. (MAINTAINERCLEANFILES): Clean it. --- Makefile.am | 44 +++++++++++++++++++++----------------------- configure.ac | 18 ++++++------------ 2 files changed, 27 insertions(+), 35 deletions(-) diff --git a/Makefile.am b/Makefile.am index ce3ad57..7602341 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,8 +21,14 @@ ## Programs. ## ## ---------- ## -bin_PROGRAMS = bin/mcron bin/crontab +bin_PROGRAMS = bin/mcron + +if MULTI_USER +bin_PROGRAMS += bin/crontab sbin_PROGRAMS = bin/cron +else +noinst_PROGRAMS = bin/cron bin/crontab +endif AM_CPPFLAGS = \ -DPACKAGE_LOAD_PATH=\"$(moduledir)\" \ @@ -160,26 +166,10 @@ EXTRA_DIST = \ #full program prefix fpp = $(DESTDIR)$(bindir)/@real_program_prefix@ +if MULTI_USER install-exec-hook: - @if [ "x@NO_VIXIE_CLOBBER@" != "xyes" -a "`id -u`" -eq "0" ]; then \ - 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); \ - $(INSTALL) -d --mode='u=rwx' $(DESTDIR)/var/cron; \ - $(INSTALL) -d --mode='u=rwx,og=rx' $(DESTDIR)/var/run; \ - $(INSTALL) -d --mode='u=rwx,og=rx' $(DESTDIR)@GUILE_SITE@; \ - $(INSTALL) -d --mode='u=rwx,og=rx' $(DESTDIR)@GUILE_SITE@/mcron; \ - elif [ "x@NO_VIXIE_CLOBBER@" = "xyes" ]; then \ - echo "Not installing Vixie-style programs"; \ - else \ - echo "+++ WARNING: NON-ROOT INSTALL: ONLY mcron WILL BE INSTALLED, NOT ANY OF THE VIXIE REPLACEMENT PROGRAMS"; \ - fi - -uninstall-hook: - if [ "`id -u`" -eq "0" ]; then \ - rm -f $(fpp){cron,crontab}$(EXEEXT); \ - fi + chmod u+s $(fpp)crontab$(EXEEXT) +endif ## --------------- ## ## Documentation. ## @@ -188,11 +178,19 @@ uninstall-hook: info_TEXINFOS = doc/mcron.texi doc_mcron_TEXINFOS = doc/fdl.texi nodist_doc_mcron_TEXINFOS = doc/config.texi -dist_man_MANS = \ - $(srcdir)/doc/mcron.1 \ +dist_man_MANS = $(srcdir)/doc/mcron.1 +extra_mans = \ $(srcdir)/doc/crontab.1 \ $(srcdir)/doc/cron.8 +if MULTI_USER +dist_man_MANS += $(extra_mans) +else +# Build, distribute, but do not install the extra man pages. +all-local: $(extra_mans) +EXTRA_DIST += $(extra_mans) +endif + # XXX: Allow the inclusion of 'doc/fdl.texi' and 'doc/config.texi' inside # 'doc/mcron.texi' for 'dvi' and 'pdf' targets. TEXI2DVI = texi2dvi -I doc @@ -218,7 +216,7 @@ $(srcdir)/doc/crontab.1: src/mcron/scripts/crontab.scm bin/crontab $(srcdir)/doc/cron.8: src/mcron/scripts/cron.scm bin/cron -@prog="cron"; man_section=8; $(gen_man) -MAINTAINERCLEANFILES = $(dist_man_MANS) +MAINTAINERCLEANFILES = $(dist_man_MANS) $(extra_mans) ## -------------- ## ## Silent rules. ## diff --git a/configure.ac b/configure.ac index 8c5fc08..363a74f 100644 --- a/configure.ac +++ b/configure.ac @@ -104,18 +104,12 @@ else fi SENDMAIL=$ac_cv_prog_SENDMAIL - -# Find out if we are avoiding Vixie. - -AC_MSG_CHECKING([whether to avoid clobbering a Vixie installation]) -AC_ARG_ENABLE(no-vixie-clobber, - AC_HELP_STRING([--enable-no-vixie-clobber], - [do not install with program names that would override a legacy cron installation]), - NO_VIXIE_CLOBBER=$enableval, - NO_VIXIE_CLOBBER=[no]) -AC_MSG_RESULT($NO_VIXIE_CLOBBER) -AC_SUBST(NO_VIXIE_CLOBBER) - +AC_ARG_ENABLE([multi-user], + [AS_HELP_STRING([--disable-multi-user], + [Don't Install legacy cron and crontab programs])], + [enable_multi_user="$enableval"], + [enable_multi_user="yes"]) +AM_CONDITIONAL([MULTI_USER], [test "x$enable_multi_user" != xyes]) # Configure the various files that mcron uses at runtime. From 02d67e7f0ec67708f9c96466c63aacf921c6577f Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Thu, 23 Feb 2017 01:52:32 +0100 Subject: [PATCH 134/239] build: Remove "maintainer-mode" configure option. * configure.ac: Remove "maintainer-mode" configure option. --- configure.ac | 4 ---- 1 file changed, 4 deletions(-) diff --git a/configure.ac b/configure.ac index 363a74f..e7ff80c 100644 --- a/configure.ac +++ b/configure.ac @@ -43,10 +43,6 @@ else fi AC_SUBST(CONFIG_DEBUG) - -# We have no interest (hence a no-op), but Debian wants this. -AC_ARG_ENABLE(maintainer-mode) - AC_CANONICAL_HOST AC_PROG_AWK AC_PROG_EGREP From 2b9828f303defc09cafa9f070d3583b4f1ac3107 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Thu, 23 Feb 2017 02:01:08 +0100 Subject: [PATCH 135/239] build: Remove "--enable-debug" configure option Unlike C code where debugging impose the "-g" compilation flags. This debugging option only affects Guile code, so using an environment variable works better since it doesn't impose to recompile Mcron or to edit "config.scm". * configure.ac: Remove "--enable-debug" configure option. * src/mcron/config.scm.in (config-debug): Use MCRON_DEBUG environment variable to trigger the debug mode at runtime. --- configure.ac | 14 -------------- src/mcron/config.scm.in | 9 ++++++++- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/configure.ac b/configure.ac index e7ff80c..c818dba 100644 --- a/configure.ac +++ b/configure.ac @@ -29,20 +29,6 @@ AC_REQUIRE_AUX_FILE([git-version-gen]) AM_INIT_AUTOMAKE([subdir-objects -Wall -Wno-override]) AM_SILENT_RULES([yes]) # enables silent rules by default -AC_MSG_CHECKING([whether debugging is requested]) -AC_ARG_ENABLE(debug, - AC_HELP_STRING([--enable-debug], - [enable debugging and traceback on error]), - CONFIG_DEBUG=$enableval, - CONFIG_DEBUG=no) -AC_MSG_RESULT($CONFIG_DEBUG) -if test "$CONFIG_DEBUG" = "no"; then - CONFIG_DEBUG="#f" -else - CONFIG_DEBUG="#t" -fi -AC_SUBST(CONFIG_DEBUG) - AC_CANONICAL_HOST AC_PROG_AWK AC_PROG_EGREP diff --git a/src/mcron/config.scm.in b/src/mcron/config.scm.in index 2b0bc7f..e6a0e07 100644 --- a/src/mcron/config.scm.in +++ b/src/mcron/config.scm.in @@ -19,7 +19,6 @@ (define-module (mcron config)) -(define-public config-debug @CONFIG_DEBUG@) (define-public config-package-name "@PACKAGE_NAME@") (define-public config-package-version "@PACKAGE_VERSION@") (define-public config-package-string "@PACKAGE_STRING@") @@ -33,3 +32,11 @@ (define-public config-deny-file "@CONFIG_DENY_FILE@") (define-public config-pid-file "@CONFIG_PID_FILE@") (define-public config-tmp-dir "@CONFIG_TMP_DIR@") + +;;; +;;; Runtime configuration +;;; + +(define-public config-debug + ;; Trigger the display of Guile stack traces on errors. + (getenv "MCRON_DEBUG")) From 9b52c0d4544b2ed0fba156f87b75632c75b2084c Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 24 Apr 2017 21:28:09 +0200 Subject: [PATCH 136/239] wrapper: Move 'wrap_env_path' to a new 'utils' module. * src/wrapper.c: Move 'wrap_env_path' to ... * src/utils.h: ... here. New module. * src/utils.c: New file. * configure.ac: Use AC_PROG_RANLIB and AM_PROG_AR. * Makefile.am (noinst_LIBRARIES, src_libmcron_a_SOURCES): New variables. (LDADD): Add 'src/libmcron.a'. --- .gitignore | 3 ++- Makefile.am | 8 +++++++- configure.ac | 2 ++ src/utils.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/utils.h | 27 +++++++++++++++++++++++++++ src/wrapper.c | 25 +------------------------ 6 files changed, 83 insertions(+), 26 deletions(-) create mode 100644 src/utils.c create mode 100644 src/utils.h diff --git a/.gitignore b/.gitignore index e9633aa..9dcc6c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ +*.[oa] *.go *.log -*.o *.trs *~ .deps @@ -8,6 +8,7 @@ /bin/cron /bin/crontab /bin/mcron +/build-aux/ar-lib /build-aux/compile /build-aux/config.guess /build-aux/config.sub diff --git a/Makefile.am b/Makefile.am index 7602341..e5a105f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,7 +36,7 @@ AM_CPPFLAGS = \ -D_GNU_SOURCE AM_CFLAGS = @GUILE_CFLAGS@ -LDADD = @GUILE_LIBS@ +LDADD = @GUILE_LIBS@ src/libmcron.a bin_mcron_SOURCES = src/wrapper.c bin_mcron_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"mcron\"" @@ -53,6 +53,12 @@ bin_crontab_DEPENDENCIES = $(compiled_modules) # wrapper to be used in the build environment and for running tests. noinst_SCRIPTS = pre-inst-env +# local library. +noinst_LIBRARIES = src/libmcron.a +src_libmcron_a_SOURCES = \ + src/utils.c \ + src/utils.h + ## --------------- ## ## Guile modules. ## ## --------------- ## diff --git a/configure.ac b/configure.ac index c818dba..98df7f9 100644 --- a/configure.ac +++ b/configure.ac @@ -33,6 +33,8 @@ AC_CANONICAL_HOST AC_PROG_AWK AC_PROG_EGREP AM_PROG_CC_C_O +AC_PROG_RANLIB +AM_PROG_AR # Check for Guile 2.x. development files GUILE_PKG([2.2 2.0]) diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..b011e77 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,44 @@ +/* utils.c -- Utility functions. + Copyright © 2017 Mathieu Lirzin + + This file is part of GNU Mcron. + + GNU Mcron is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GNU Mcron is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Mcron. If not, see . */ + +#include "utils.h" +#include +#include +#include +#include + +void +wrap_env_path (const char *envar, const char *dir) +{ + const char *path = getenv (envar); + if (path == NULL) + setenv (envar, dir, true); + else + { + char *new_path; + int ret = asprintf (&new_path, "%s:%s", dir, path); + if (ret >= 0) + setenv (envar, new_path, true); + else + { + perror (envar); + exit (EXIT_FAILURE); + } + free (new_path); + } +} diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..5a71afd --- /dev/null +++ b/src/utils.h @@ -0,0 +1,27 @@ +/* utils.h -- Utility functions. + Copyright © 2017 Mathieu Lirzin + + This file is part of GNU Mcron. + + GNU Mcron is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GNU Mcron is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Mcron. If not, see . */ + +#ifndef MCRON_UTILS_H +#define MCRON_UTILS_H + +/** + Append DIR in front of ENVAR environment variable value. If ENVAR is not + defined, then define it with DIR. Bail out if something went wrong. */ +extern void wrap_env_path (const char *envar, const char *dir); + +#endif /* MCRON_UTILS_H */ diff --git a/src/wrapper.c b/src/wrapper.c index cef6b3c..d5be805 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -21,6 +21,7 @@ is needed because the crontab personality requires SUID which is not permitted for executable scripts. */ +#include "utils.h" #include #include #include @@ -29,7 +30,6 @@ #include /* Forward declarations. */ -static void wrap_env_path (const char *envar, const char *dir); static void inner_main (void *closure, int argc, char **argv); static void react_to_terminal_signal (int sig); static SCM set_cron_signals (void); @@ -51,29 +51,6 @@ main (int argc, char **argv) return EXIT_SUCCESS; } -/* Append DIR in front of ENVAR environment variable value. If ENVAR is not - defined, then define it with DIR. Bail out if something went wrong. */ -static void -wrap_env_path (const char *envar, const char *dir) -{ - const char *path = getenv (envar); - if (path == NULL) - setenv (envar, dir, true); - else - { - char *new_path; - int ret = asprintf (&new_path, "%s:%s", dir, path); - if (ret >= 0) - setenv (envar, new_path, true); - else - { - perror (envar); - exit (EXIT_FAILURE); - } - free (new_path); - } -} - /* Launch the Mcron Guile main program. */ static void inner_main (void *closure, int argc, char **argv) From c01106387f6d0866ef6fd4801473984cc642e60b Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 25 Apr 2017 00:29:32 +0200 Subject: [PATCH 137/239] Replace generic C wrapper with individual programs * src/wrapper.c: Delete. * src/crontab.c: New file. * src/mcron.c: Likewise. * src/cron.c: Likewise. * configure.ac: Adapt 'AC_CONFIG_DIR' to use "src/mcron.c". * Makefile.am (bin_crontab_SOURCES, bin_cron_SOURCES) (bin_mcron_SOURCES): Use new files. (bin_cron_CPPFLAGS, bin_mcron_CPPFLAGS, bin_crontab_CPPFLAGS): Delete. --- Makefile.am | 9 +++---- configure.ac | 2 +- src/{wrapper.c => cron.c} | 32 +++++++++---------------- src/crontab.c | 49 +++++++++++++++++++++++++++++++++++++++ src/mcron.c | 49 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 113 insertions(+), 28 deletions(-) rename src/{wrapper.c => cron.c} (66%) create mode 100644 src/crontab.c create mode 100644 src/mcron.c diff --git a/Makefile.am b/Makefile.am index e5a105f..edca6a9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,16 +38,13 @@ AM_CPPFLAGS = \ AM_CFLAGS = @GUILE_CFLAGS@ LDADD = @GUILE_LIBS@ src/libmcron.a -bin_mcron_SOURCES = src/wrapper.c -bin_mcron_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"mcron\"" +bin_mcron_SOURCES = src/mcron.c bin_mcron_DEPENDENCIES = $(compiled_modules) -bin_cron_SOURCES = src/wrapper.c -bin_cron_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"cron\"" +bin_cron_SOURCES = src/cron.c bin_cron_DEPENDENCIES = $(compiled_modules) -bin_crontab_SOURCES = src/wrapper.c -bin_crontab_CPPFLAGS = $(AM_CPPFLAGS) -DPROGRAM="\"crontab\"" +bin_crontab_SOURCES = src/crontab.c bin_crontab_DEPENDENCIES = $(compiled_modules) # wrapper to be used in the build environment and for running tests. diff --git a/configure.ac b/configure.ac index 98df7f9..0ce6475 100644 --- a/configure.ac +++ b/configure.ac @@ -22,7 +22,7 @@ AC_PREREQ(2.61) AC_INIT([GNU Mcron], m4_esyscmd([build-aux/git-version-gen .tarball-version]), [bug-mcron@gnu.org]) -AC_CONFIG_SRCDIR([src/wrapper.c]) +AC_CONFIG_SRCDIR([src/mcron.c]) AC_CONFIG_AUX_DIR([build-aux]) AC_REQUIRE_AUX_FILE([test-driver.scm]) AC_REQUIRE_AUX_FILE([git-version-gen]) diff --git a/src/wrapper.c b/src/cron.c similarity index 66% rename from src/wrapper.c rename to src/cron.c index d5be805..55bcaaf 100644 --- a/src/wrapper.c +++ b/src/cron.c @@ -1,4 +1,4 @@ -/* wrapper.c -- C code booting Guile +/* cron.c -- run jobs at scheduled times Copyright © 2003, 2014 Dale Mellor Copyright © 2015, 2016, 2017 Mathieu Lirzin @@ -17,25 +17,17 @@ You should have received a copy of the GNU General Public License along with GNU Mcron. If not, see . */ -/* This C code represents a thin wrapper around the Guile code of Mcron. It - is needed because the crontab personality requires SUID which is not - permitted for executable scripts. */ - #include "utils.h" #include #include -#include -#include -#include -#include /* Forward declarations. */ -static void inner_main (void *closure, int argc, char **argv); +static void inner_main (void *closure, int argc, char *argv[]); static void react_to_terminal_signal (int sig); static SCM set_cron_signals (void); int -main (int argc, char **argv) +main (int argc, char *argv[]) { /* Set Guile load paths to ensure that Mcron modules will be found after installation. In a build environment let the 'pre-inst-env' script set @@ -46,25 +38,23 @@ main (int argc, char **argv) wrap_env_path ("GUILE_LOAD_COMPILED_PATH", PACKAGE_LOAD_COMPILED_PATH); } - scm_boot_guile (argc, argv, inner_main, 0); + scm_boot_guile (argc, argv, inner_main, NULL); return EXIT_SUCCESS; } /* Launch the Mcron Guile main program. */ static void -inner_main (void *closure, int argc, char **argv) +inner_main (void *closure, int argc, char *argv[]) { - scm_set_current_module (scm_c_resolve_module ("mcron scripts " PROGRAM)); - /* Register the procedures to be called from Guile. */ + scm_set_current_module (scm_c_resolve_module ("mcron scripts cron")); scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); - /* Call main procedure. */ scm_call_0 (scm_variable_ref (scm_c_lookup ("main"))); } -/* Set up all the signal handlers as required by the cron personality. This - is necessary to perform the signal processing in C because the sigaction - function won't work when called from Guile. */ +/* Set up all the signal handlers. This is necessary to perform the signal + processing in C because the sigaction function won't work when called from + Guile. */ static SCM set_cron_signals () { @@ -80,8 +70,8 @@ set_cron_signals () return SCM_BOOL_T; } -/* Handle signal SIG and exit. All signals that mcron handles will produce - the same behavior so we don't need to use SIG in the implementation. */ +/* Handle signal SIG and exit. All signals that cron handles will produce the + same behavior so we don't need to use SIG in the implementation. */ static void react_to_terminal_signal (int sig) { diff --git a/src/crontab.c b/src/crontab.c new file mode 100644 index 0000000..a432f1d --- /dev/null +++ b/src/crontab.c @@ -0,0 +1,49 @@ +/* crontab.c -- edit users' crontab files + Copyright © 2003, 2014 Dale Mellor + Copyright © 2015, 2016, 2017 Mathieu Lirzin + + This file is part of GNU Mcron. + + GNU Mcron is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GNU Mcron is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Mcron. If not, see . */ + +#include "utils.h" +#include + +/* Forward declarations. */ +static void inner_main (void *closure, int argc, char *argv[]); + +int +main (int argc, char *argv[]) +{ + /* Set Guile load paths to ensure that Mcron modules will be found after + installation. In a build environment let the 'pre-inst-env' script set + the correct paths. */ + if (getenv ("MCRON_UNINSTALLED") == NULL) + { + wrap_env_path ("GUILE_LOAD_PATH", PACKAGE_LOAD_PATH); + wrap_env_path ("GUILE_LOAD_COMPILED_PATH", PACKAGE_LOAD_COMPILED_PATH); + } + + scm_boot_guile (argc, argv, inner_main, NULL); + + return EXIT_SUCCESS; +} + +/* Launch the Mcron Guile main program. */ +static void +inner_main (void *closure, int argc, char *argv[]) +{ + scm_set_current_module (scm_c_resolve_module ("mcron scripts crontab")); + scm_call_0 (scm_variable_ref (scm_c_lookup ("main"))); +} diff --git a/src/mcron.c b/src/mcron.c new file mode 100644 index 0000000..43afc72 --- /dev/null +++ b/src/mcron.c @@ -0,0 +1,49 @@ +/* mcron.c -- run jobs at scheduled times + Copyright © 2003, 2014 Dale Mellor + Copyright © 2015, 2016, 2017 Mathieu Lirzin + + This file is part of GNU Mcron. + + GNU Mcron is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GNU Mcron is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Mcron. If not, see . */ + +#include "utils.h" +#include + +/* Forward declarations. */ +static void inner_main (void *closure, int argc, char *argv[]); + +int +main (int argc, char *argv[]) +{ + /* Set Guile load paths to ensure that Mcron modules will be found after + installation. In a build environment let the 'pre-inst-env' script set + the correct paths. */ + if (getenv ("MCRON_UNINSTALLED") == NULL) + { + wrap_env_path ("GUILE_LOAD_PATH", PACKAGE_LOAD_PATH); + wrap_env_path ("GUILE_LOAD_COMPILED_PATH", PACKAGE_LOAD_COMPILED_PATH); + } + + scm_boot_guile (argc, argv, inner_main, NULL); + + return EXIT_SUCCESS; +} + +/* Launch the Mcron Guile main program. */ +static void +inner_main (void *closure, int argc, char *argv[]) +{ + scm_set_current_module (scm_c_resolve_module ("mcron scripts mcron")); + scm_call_0 (scm_variable_ref (scm_c_lookup ("main"))); +} From d01195784352b29fe13d0676a2f50d60371d007f Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 25 Apr 2017 16:32:49 +0200 Subject: [PATCH 138/239] mcron: Handle command line arguments in C with argp 'argp' is a convenient and maintainable way to parse command line arguments. Guile doesn't offer an equivalent of this, so the command line handling has been moved to C. * src/mcron.c (parse_args, parse_opt): New functions. (inner_main): Call 'parse_args'. * src/mcron/scripts/mcron.scm (show-help, %options): Delete. (main): Remove command line handling. --- src/mcron.c | 82 +++++++++++++++++++++++++++++++++- src/mcron/scripts/mcron.scm | 87 ++++++++++++------------------------- 2 files changed, 108 insertions(+), 61 deletions(-) diff --git a/src/mcron.c b/src/mcron.c index 43afc72..5c63c4b 100644 --- a/src/mcron.c +++ b/src/mcron.c @@ -18,10 +18,13 @@ along with GNU Mcron. If not, see . */ #include "utils.h" +#include #include /* Forward declarations. */ static void inner_main (void *closure, int argc, char *argv[]); +static SCM parse_args (int argc, char *argv[]); +static error_t parse_opt (int key, char *arg, struct argp_state *state); int main (int argc, char *argv[]) @@ -44,6 +47,83 @@ main (int argc, char *argv[]) static void inner_main (void *closure, int argc, char *argv[]) { + SCM config = parse_args (argc, argv); scm_set_current_module (scm_c_resolve_module ("mcron scripts mcron")); - scm_call_0 (scm_variable_ref (scm_c_lookup ("main"))); + scm_call_1 (scm_variable_ref (scm_c_lookup ("main")), config); +} + +/* Handle command line arguments. */ +static SCM +parse_args (int argc, char *argv[]) +{ + static struct argp_option options[] = { + {"schedule", 's', "N", 0, + "Display the next N jobs that will be run"}, + {"daemon", 'd', 0, 0, + "Run as a daemon process"}, + {"stdin", 'i', "FORMAT", 0, + "Format of data passed as standard input or file arguments (default guile)"}, + {0, 0, 0, 0, 0} + }; + + static struct argp argp = { + .options = options, + .parser = parse_opt, + .args_doc = "[FILE...]", + .doc = "Run an mcron process according to the specifications in the " + "FILE... (`-' for standard input), or use all the files in " + "~/.config/cron (or the deprecated ~/.cron) with .guile or " + ".vixie extensions." + }; + + SCM config = SCM_EOL; + argp_program_version = PACKAGE_STRING; + argp_program_bug_address = PACKAGE_BUGREPORT; + argp_parse (&argp, argc, argv, 0, NULL, &config); + + return config; +} + +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + SCM *config = state->input; + + switch (key) + { + case 's': + *config = scm_assq_set_x (*config, scm_from_utf8_symbol ("schedule"), + scm_from_int (atoi (arg))); + break; + case 'd': + *config = scm_assq_set_x (*config, scm_from_utf8_symbol ("daemon"), + SCM_BOOL_T); + break; + case 'i': + if (strncmp (arg, "vixie", 6) == 0) + *config = scm_assq_set_x (*config, scm_from_utf8_symbol ("vixie"), + SCM_BOOL_T); + break; + case ARGP_KEY_NO_ARGS: + *config = scm_assq_set_x (*config, scm_from_utf8_symbol ("files"), + SCM_EOL); + break; + case ARGP_KEY_ARGS: + { + SCM lst = SCM_EOL; + int filec = state->argc - state->next; + char **filev = state->argv + state->next; + + for (int i = filec - 1; i >= 0; i--) + lst = scm_cons (scm_from_locale_string (filev[i]), lst); + + *config = scm_assq_set_x (*config, scm_from_utf8_symbol ("files"), + lst); + break; + } + case ARGP_KEY_ARG: + default: + return ARGP_ERR_UNKNOWN; + } + return 0; } diff --git a/src/mcron/scripts/mcron.scm b/src/mcron/scripts/mcron.scm index b6c7729..588734b 100644 --- a/src/mcron/scripts/mcron.scm +++ b/src/mcron/scripts/mcron.scm @@ -25,34 +25,6 @@ #:use-module (mcron vixie-specification) #:export (main)) -(define (show-help) - (display "Usage: mcron [OPTIONS] [FILES] -Run an mcron process according to the specifications in the FILES (`-' for -standard input), or use all the files in ~/.config/cron (or the -deprecated ~/.cron) with .guile or .vixie extensions. - - -v, --version Display version - -h, --help Display this help message - -sN, --schedule[=]N Display the next N jobs that will be run by mcron - -d, --daemon Immediately detach the program from the terminal - and run as a daemon process - -i, --stdin=(guile|vixie) Format of data passed as standard input or - file arguments (default guile)") - (newline) - (show-package-information)) - -(define %options - `((schedule (single-char #\s) (value #t) - (predicate ,(λ (str) (string->number str)))) - (daemon (single-char #\d) (value #f)) - (noetc (single-char #\n) (value #f)) - (stdin (single-char #\i) (value #t) - (predicate ,(λ (val) - (or (string=? val "guile") - (string=? val "vixie"))))) - (version (single-char #\v) (value #f)) - (help (single-char #\h) (value #f)))) - (define process-user-file (let ((guile-regexp (make-regexp "\\.gui(le)?$")) (vixie-regexp (make-regexp "\\.vix(ie)?$"))) @@ -102,35 +74,30 @@ $XDG_CONFIG_HOME is not defined uses ~/.config/cron instead)." ;;; Entry point. ;;; -(define* (main #:optional (args (command-line))) - (let ((opts (parse-args args %options))) - (when config-debug - (debug-enable 'backtrace)) - (cond ((option-ref opts 'help #f) - (show-help) - (exit 0)) - ((option-ref opts 'version #f) - (show-version "mcron") - (exit 0)) - (else - (%process-files (option-ref opts '() '()) - (option-ref opts 'stdin "guile")) - (cond ((option-ref opts 'schedule #f) ;display jobs schedule - => (λ (count) - (display (get-schedule (max 1 (string->number count)))) - (exit 0))) - ((option-ref opts 'daemon #f) ;run mcron as a daemon - (case (primitive-fork) - ((0) (setsid)) - (else (exit 0))))) - ;; Forever execute the 'run-job-loop', and when it drops out (can - ;; only be because a message has come in on the socket) we process - ;; the socket request before restarting the loop again. - (catch-mcron-error - (let ((fdes-list '())) - (while #t - (run-job-loop fdes-list) - ;; we can also drop out of run-job-loop because of a SIGCHLD, - ;; so must test FDES-LIST. - (unless (null? fdes-list) - (process-update-request fdes-list))))))))) +(define* (main #:optional (opts '())) + (when config-debug + (debug-enable 'backtrace)) + + (%process-files (or (assq-ref opts 'files) '()) + (if (assq-ref opts 'vixie) "vixie" "guile")) + + (cond ((assq-ref opts 'schedule) ;display jobs schedule + => (λ (count) + (display (get-schedule (max 1 count))) + (exit 0))) + ((assq-ref opts 'daemon) ;run mcron as a daemon + (case (primitive-fork) + ((0) (setsid)) + (else (exit 0))))) + + ;; Forever execute the 'run-job-loop', and when it drops out (can + ;; only be because a message has come in on the socket) we process + ;; the socket request before restarting the loop again. + (catch-mcron-error + (let ((fdes-list '())) + (while #t + (run-job-loop fdes-list) + ;; we can also drop out of run-job-loop because of a SIGCHLD, + ;; so must test FDES-LIST. + (unless (null? fdes-list) + (process-update-request fdes-list)))))) From dd30cb9e547f90d0bffc8eb758c58bba0e2c08ad Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 26 Apr 2017 21:54:13 +0200 Subject: [PATCH 139/239] utils: Add 'assq_symbol_set_x' function * src/utils.c (assq_symbol_set_x): New function. * src/mcron.c (parse_opt): Use it. --- src/cron.c | 1 - src/crontab.c | 1 - src/mcron.c | 17 ++++++----------- src/utils.c | 9 ++++++--- src/utils.h | 6 ++++++ 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/cron.c b/src/cron.c index 55bcaaf..369f1d1 100644 --- a/src/cron.c +++ b/src/cron.c @@ -18,7 +18,6 @@ along with GNU Mcron. If not, see . */ #include "utils.h" -#include #include /* Forward declarations. */ diff --git a/src/crontab.c b/src/crontab.c index a432f1d..16c0be6 100644 --- a/src/crontab.c +++ b/src/crontab.c @@ -18,7 +18,6 @@ along with GNU Mcron. If not, see . */ #include "utils.h" -#include /* Forward declarations. */ static void inner_main (void *closure, int argc, char *argv[]); diff --git a/src/mcron.c b/src/mcron.c index 5c63c4b..22cc680 100644 --- a/src/mcron.c +++ b/src/mcron.c @@ -19,7 +19,6 @@ #include "utils.h" #include -#include /* Forward declarations. */ static void inner_main (void *closure, int argc, char *argv[]); @@ -92,21 +91,18 @@ parse_opt (int key, char *arg, struct argp_state *state) switch (key) { case 's': - *config = scm_assq_set_x (*config, scm_from_utf8_symbol ("schedule"), - scm_from_int (atoi (arg))); + assq_symbol_set_x (config, "schedule", + scm_from_int (atoi (arg))); break; case 'd': - *config = scm_assq_set_x (*config, scm_from_utf8_symbol ("daemon"), - SCM_BOOL_T); + assq_symbol_set_x (config, "daemon", SCM_BOOL_T); break; case 'i': if (strncmp (arg, "vixie", 6) == 0) - *config = scm_assq_set_x (*config, scm_from_utf8_symbol ("vixie"), - SCM_BOOL_T); + assq_symbol_set_x (config, "vixie", SCM_BOOL_T); break; case ARGP_KEY_NO_ARGS: - *config = scm_assq_set_x (*config, scm_from_utf8_symbol ("files"), - SCM_EOL); + assq_symbol_set_x (config, "files", SCM_EOL); break; case ARGP_KEY_ARGS: { @@ -117,8 +113,7 @@ parse_opt (int key, char *arg, struct argp_state *state) for (int i = filec - 1; i >= 0; i--) lst = scm_cons (scm_from_locale_string (filev[i]), lst); - *config = scm_assq_set_x (*config, scm_from_utf8_symbol ("files"), - lst); + assq_symbol_set_x (config, "files", lst); break; } case ARGP_KEY_ARG: diff --git a/src/utils.c b/src/utils.c index b011e77..3ea05f3 100644 --- a/src/utils.c +++ b/src/utils.c @@ -18,9 +18,6 @@ #include "utils.h" #include -#include -#include -#include void wrap_env_path (const char *envar, const char *dir) @@ -42,3 +39,9 @@ wrap_env_path (const char *envar, const char *dir) free (new_path); } } + +void +assq_symbol_set_x (SCM *alst, const char *symbol, SCM val) +{ + *alst = scm_assq_set_x (*alst, scm_from_utf8_symbol (symbol), val); +} diff --git a/src/utils.h b/src/utils.h index 5a71afd..910483f 100644 --- a/src/utils.h +++ b/src/utils.h @@ -19,9 +19,15 @@ #ifndef MCRON_UTILS_H #define MCRON_UTILS_H +#include + /** Append DIR in front of ENVAR environment variable value. If ENVAR is not defined, then define it with DIR. Bail out if something went wrong. */ extern void wrap_env_path (const char *envar, const char *dir); +/** + In the association list pointed by ALST, set SYMBOL to VAL. */ +extern void assq_symbol_set_x (SCM *alst, const char *symbol, SCM val); + #endif /* MCRON_UTILS_H */ From 811ad9167a0dc4fe9e13dd20d534d477469dc682 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Thu, 28 Sep 2017 14:21:18 +0200 Subject: [PATCH 140/239] doc: Use 'unless' form * doc/mcron.texi (Invoking cron or crond): Use 'unless' form and put "/etc/crontab" inside a @code command. --- doc/mcron.texi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/mcron.texi b/doc/mcron.texi index a59505d..70e9d98 100644 --- a/doc/mcron.texi +++ b/doc/mcron.texi @@ -913,9 +913,9 @@ 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. +Further, unless the @code{--noetc} option is used, a job is scheduled to run +every minute to check if @code{/etc/crontab} has been modified. If so, this +file will also be re-read. The options which may be used with this program are as follows. From c285d36ab2a48f09c14655a0dcec5895700fe4dd Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Thu, 28 Sep 2017 17:59:40 +0200 Subject: [PATCH 141/239] tests: Add 'basic.sh' * tests/init.sh: New test framework from Gnulib. * tests/basic.sh: New test. * Makefile.am (TESTS): Add it. (TEST_EXTENSIONS): Add '.sh'. (SH_LOG_COMPILER): Use 'pre-inst-env'. (EXTRA_DIST): Add 'tests/init.sh'. * build-aux/pre-inst-env.in: export $srcdir for shell tests. --- .gitignore | 1 + Makefile.am | 6 +- build-aux/pre-inst-env.in | 3 + tests/basic.sh | 33 +++ tests/init.sh | 605 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 647 insertions(+), 1 deletion(-) create mode 100644 tests/basic.sh create mode 100644 tests/init.sh diff --git a/.gitignore b/.gitignore index 9dcc6c8..a9f5414 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ /build-aux/install-sh /build-aux/mdate-sh /build-aux/missing +/build-aux/test-driver /build-aux/texinfo.tex /doc/config.texi /doc/cron.8 diff --git a/Makefile.am b/Makefile.am index edca6a9..84cbf23 100644 --- a/Makefile.am +++ b/Makefile.am @@ -124,14 +124,17 @@ DISTCLEANFILES = src/mcron/config.scm ## Test suite. ## ## ------------ ## -TEST_EXTENSIONS = .scm +TEST_EXTENSIONS = .scm .sh AM_TESTS_ENVIRONMENT = env GUILE_AUTO_COMPILE='0' +SH_LOG_COMPILER = ./pre-inst-env $(SHELL) + SCM_LOG_DRIVER = \ $(builddir)/pre-inst-env $(GUILE) \ $(srcdir)/build-aux/test-driver.scm TESTS = \ + tests/basic.sh \ tests/environment.scm \ tests/job-specifier.scm @@ -160,6 +163,7 @@ gen-ChangeLog: EXTRA_DIST = \ bootstrap \ build-aux/guix.scm \ + tests/init.sh \ $(TESTS) ## -------------- ## diff --git a/build-aux/pre-inst-env.in b/build-aux/pre-inst-env.in index 75a8d70..aefe33e 100644 --- a/build-aux/pre-inst-env.in +++ b/build-aux/pre-inst-env.in @@ -32,4 +32,7 @@ export PATH MCRON_UNINSTALLED=1 export MCRON_UNINSTALLED +srcdir="@srcdir@" +export srcdir + exec "$@" diff --git a/tests/basic.sh b/tests/basic.sh new file mode 100644 index 0000000..07b664b --- /dev/null +++ b/tests/basic.sh @@ -0,0 +1,33 @@ +# basic.sh -- basic tests for mcron +# Copyright © 2017 Mathieu Lirzin +# +# This file is part of GNU Mcron. +# +# GNU Mcron is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNU Mcron is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Mcron. If not, see . + +source "${srcdir}/tests/init.sh" + +# Use current working directory to store mcron files +XDG_CONFIG_HOME=`pwd` +export XDG_CONFIG_HOME + +mkdir cron +cat > cron/foo.guile < "output$$" +grep -e "foo" "output$$" || fail_ "'foo.guile' job is not scheduled" + +Exit 0 diff --git a/tests/init.sh b/tests/init.sh new file mode 100644 index 0000000..470605c --- /dev/null +++ b/tests/init.sh @@ -0,0 +1,605 @@ +# source this file; set up for tests + +# Copyright (C) 2009-2017 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Using this file in a test +# ========================= +# +# The typical skeleton of a test looks like this: +# +# #!/bin/sh +# . "${srcdir=.}/init.sh"; path_prepend_ . +# Execute some commands. +# Note that these commands are executed in a subdirectory, therefore you +# need to prepend "../" to relative filenames in the build directory. +# Note that the "path_prepend_ ." is useful only if the body of your +# test invokes programs residing in the initial directory. +# For example, if the programs you want to test are in src/, and this test +# script is named tests/test-1, then you would use "path_prepend_ ../src", +# or perhaps export PATH='$(abs_top_builddir)/src$(PATH_SEPARATOR)'"$$PATH" +# to all tests via automake's TESTS_ENVIRONMENT. +# Set the exit code 0 for success, 77 for skipped, or 1 or other for failure. +# Use the skip_ and fail_ functions to print a diagnostic and then exit +# with the corresponding exit code. +# Exit $? + +# Executing a test that uses this file +# ==================================== +# +# Running a single test: +# $ make check TESTS=test-foo.sh +# +# Running a single test, with verbose output: +# $ make check TESTS=test-foo.sh VERBOSE=yes +# +# Running a single test, keeping the temporary directory: +# $ make check TESTS=test-foo.sh KEEP=yes +# +# Running a single test, with single-stepping: +# 1. Go into a sub-shell: +# $ bash +# 2. Set relevant environment variables from TESTS_ENVIRONMENT in the +# Makefile: +# $ export srcdir=../../tests # this is an example +# 3. Execute the commands from the test, copy&pasting them one by one: +# $ . "$srcdir/init.sh"; path_prepend_ . +# ... +# 4. Finally +# $ exit + +ME_=`expr "./$0" : '.*/\(.*\)$'` + +# We use a trap below for cleanup. This requires us to go through +# hoops to get the right exit status transported through the handler. +# So use 'Exit STATUS' instead of 'exit STATUS' inside of the tests. +# Turn off errexit here so that we don't trip the bug with OSF1/Tru64 +# sh inside this function. +Exit () { set +e; (exit $1); exit $1; } + +# Print warnings (e.g., about skipped and failed tests) to this file number. +# Override by defining to say, 9, in init.cfg, and putting say, +# export ...ENVVAR_SETTINGS...; $(SHELL) 9>&2 +# in the definition of TESTS_ENVIRONMENT in your tests/Makefile.am file. +# This is useful when using automake's parallel tests mode, to print +# the reason for skip/failure to console, rather than to the .log files. +: ${stderr_fileno_=2} + +# Note that correct expansion of "$*" depends on IFS starting with ' '. +# Always write the full diagnostic to stderr. +# When stderr_fileno_ is not 2, also emit the first line of the +# diagnostic to that file descriptor. +warn_ () +{ + # If IFS does not start with ' ', set it and emit the warning in a subshell. + case $IFS in + ' '*) printf '%s\n' "$*" >&2 + test $stderr_fileno_ = 2 \ + || { printf '%s\n' "$*" | sed 1q >&$stderr_fileno_ ; } ;; + *) (IFS=' '; warn_ "$@");; + esac +} +fail_ () { warn_ "$ME_: failed test: $@"; Exit 1; } +skip_ () { warn_ "$ME_: skipped test: $@"; Exit 77; } +fatal_ () { warn_ "$ME_: hard error: $@"; Exit 99; } +framework_failure_ () { warn_ "$ME_: set-up failure: $@"; Exit 99; } + +# This is used to simplify checking of the return value +# which is useful when ensuring a command fails as desired. +# I.e., just doing `command ... &&fail=1` will not catch +# a segfault in command for example. With this helper you +# instead check an explicit exit code like +# returns_ 1 command ... || fail +returns_ () { + # Disable tracing so it doesn't interfere with stderr of the wrapped command + { set +x; } 2>/dev/null + + local exp_exit="$1" + shift + "$@" + test $? -eq $exp_exit && ret_=0 || ret_=1 + + if test "$VERBOSE" = yes && test "$gl_set_x_corrupts_stderr_" = false; then + set -x + fi + { return $ret_; } 2>/dev/null +} + +# Sanitize this shell to POSIX mode, if possible. +DUALCASE=1; export DUALCASE +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; + esac +fi + +# We require $(...) support unconditionally. +# We require non-surprising "local" semantics (this eliminates dash). +# This takes the admittedly draconian step of eliminating dash, because the +# assignment tab=$(printf '\t') works fine, yet preceding it with "local " +# transforms it into an assignment that sets the variable to the empty string. +# That is too counter-intuitive, and can lead to subtle run-time malfunction. +# The example below is less subtle in that with dash, it evokes the run-time +# exception "dash: 1: local: 1: bad variable name". +# We require a few additional shell features only when $EXEEXT is nonempty, +# in order to support automatic $EXEEXT emulation: +# - hyphen-containing alias names +# - we prefer to use ${var#...} substitution, rather than having +# to work around lack of support for that feature. +# The following code attempts to find a shell with support for these features. +# If the current shell passes the test, we're done. Otherwise, test other +# shells until we find one that passes. If one is found, re-exec it. +# If no acceptable shell is found, skip the current test. +# +# The "...set -x; P=1 true 2>err..." test is to disqualify any shell that +# emits "P=1" into err, as /bin/sh from SunOS 5.11 and OpenBSD 4.7 do. +# +# Use "9" to indicate success (rather than 0), in case some shell acts +# like Solaris 10's /bin/sh but exits successfully instead of with status 2. + +# Eval this code in a subshell to determine a shell's suitability. +# 10 - passes all tests; ok to use +# 9 - ok, but enabling "set -x" corrupts app stderr; prefer higher score +# ? - not ok +gl_shell_test_script_=' +test $(echo y) = y || exit 1 +f_local_() { local v=1; }; f_local_ || exit 1 +f_dash_local_fail_() { local t=$(printf " 1"); }; f_dash_local_fail_ +score_=10 +if test "$VERBOSE" = yes; then + test -n "$( (exec 3>&1; set -x; P=1 true 2>&3) 2> /dev/null)" && score_=9 +fi +test -z "$EXEEXT" && exit $score_ +shopt -s expand_aliases +alias a-b="echo zoo" +v=abx + test ${v%x} = ab \ + && test ${v#a} = bx \ + && test $(a-b) = zoo \ + && exit $score_ +' + +if test "x$1" = "x--no-reexec"; then + shift +else + # Assume a working shell. Export to subshells (setup_ needs this). + gl_set_x_corrupts_stderr_=false + export gl_set_x_corrupts_stderr_ + + # Record the first marginally acceptable shell. + marginal_= + + # Search for a shell that meets our requirements. + for re_shell_ in __current__ "${CONFIG_SHELL:-no_shell}" \ + /bin/sh bash dash zsh pdksh fail + do + test "$re_shell_" = no_shell && continue + + # If we've made it all the way to the sentinel, "fail" without + # finding even a marginal shell, skip this test. + if test "$re_shell_" = fail; then + test -z "$marginal_" && skip_ failed to find an adequate shell + re_shell_=$marginal_ + break + fi + + # When testing the current shell, simply "eval" the test code. + # Otherwise, run it via $re_shell_ -c ... + if test "$re_shell_" = __current__; then + # 'eval'ing this code makes Solaris 10's /bin/sh exit with + # $? set to 2. It does not evaluate any of the code after the + # "unexpected" first '('. Thus, we must run it in a subshell. + ( eval "$gl_shell_test_script_" ) > /dev/null 2>&1 + else + "$re_shell_" -c "$gl_shell_test_script_" 2>/dev/null + fi + + st_=$? + + # $re_shell_ works just fine. Use it. + if test $st_ = 10; then + gl_set_x_corrupts_stderr_=false + break + fi + + # If this is our first marginally acceptable shell, remember it. + if test "$st_:$marginal_" = 9: ; then + marginal_="$re_shell_" + gl_set_x_corrupts_stderr_=true + fi + done + + if test "$re_shell_" != __current__; then + # Found a usable shell. Preserve -v and -x. + case $- in + *v*x* | *x*v*) opts_=-vx ;; + *v*) opts_=-v ;; + *x*) opts_=-x ;; + *) opts_= ;; + esac + re_shell=$re_shell_ + export re_shell + exec "$re_shell_" $opts_ "$0" --no-reexec "$@" + echo "$ME_: exec failed" 1>&2 + exit 127 + fi +fi + +# If this is bash, turn off all aliases. +test -n "$BASH_VERSION" && unalias -a + +# Note that when supporting $EXEEXT (transparently mapping from PROG_NAME to +# PROG_NAME.exe), we want to support hyphen-containing names like test-acos. +# That is part of the shell-selection test above. Why use aliases rather +# than functions? Because support for hyphen-containing aliases is more +# widespread than that for hyphen-containing function names. +test -n "$EXEEXT" && shopt -s expand_aliases + +# Enable glibc's malloc-perturbing option. +# This is useful for exposing code that depends on the fact that +# malloc-related functions often return memory that is mostly zeroed. +# If you have the time and cycles, use valgrind to do an even better job. +: ${MALLOC_PERTURB_=87} +export MALLOC_PERTURB_ + +# This is a stub function that is run upon trap (upon regular exit and +# interrupt). Override it with a per-test function, e.g., to unmount +# a partition, or to undo any other global state changes. +cleanup_ () { :; } + +# Emit a header similar to that from diff -u; Print the simulated "diff" +# command so that the order of arguments is clear. Don't bother with @@ lines. +emit_diff_u_header_ () +{ + printf '%s\n' "diff -u $*" \ + "--- $1 1970-01-01" \ + "+++ $2 1970-01-01" +} + +# Arrange not to let diff or cmp operate on /dev/null, +# since on some systems (at least OSF/1 5.1), that doesn't work. +# When there are not two arguments, or no argument is /dev/null, return 2. +# When one argument is /dev/null and the other is not empty, +# cat the nonempty file to stderr and return 1. +# Otherwise, return 0. +compare_dev_null_ () +{ + test $# = 2 || return 2 + + if test "x$1" = x/dev/null; then + test -s "$2" || return 0 + emit_diff_u_header_ "$@"; sed 's/^/+/' "$2" + return 1 + fi + + if test "x$2" = x/dev/null; then + test -s "$1" || return 0 + emit_diff_u_header_ "$@"; sed 's/^/-/' "$1" + return 1 + fi + + return 2 +} + +for diff_opt_ in -u -U3 -c '' no; do + test "$diff_opt_" != no && + diff_out_=`exec 2>/dev/null; diff $diff_opt_ "$0" "$0" < /dev/null` && + break +done +if test "$diff_opt_" != no; then + if test -z "$diff_out_"; then + compare_ () { diff $diff_opt_ "$@"; } + else + compare_ () + { + # If no differences were found, AIX and HP-UX 'diff' produce output + # like "No differences encountered". Hide this output. + diff $diff_opt_ "$@" > diff.out + diff_status_=$? + test $diff_status_ -eq 0 || cat diff.out || diff_status_=2 + rm -f diff.out || diff_status_=2 + return $diff_status_ + } + fi +elif cmp -s /dev/null /dev/null 2>/dev/null; then + compare_ () { cmp -s "$@"; } +else + compare_ () { cmp "$@"; } +fi + +# Usage: compare EXPECTED ACTUAL +# +# Given compare_dev_null_'s preprocessing, defer to compare_ if 2 or more. +# Otherwise, propagate $? to caller: any diffs have already been printed. +compare () +{ + # This looks like it can be factored to use a simple "case $?" + # after unchecked compare_dev_null_ invocation, but that would + # fail in a "set -e" environment. + if compare_dev_null_ "$@"; then + return 0 + else + case $? in + 1) return 1;; + *) compare_ "$@";; + esac + fi +} + +# An arbitrary prefix to help distinguish test directories. +testdir_prefix_ () { printf gt; } + +# Run the user-overridable cleanup_ function, remove the temporary +# directory and exit with the incoming value of $?. +remove_tmp_ () +{ + __st=$? + cleanup_ + if test "$KEEP" = yes; then + echo "Not removing temporary directory $test_dir_" + else + # cd out of the directory we're about to remove + cd "$initial_cwd_" || cd / || cd /tmp + chmod -R u+rwx "$test_dir_" + # If removal fails and exit status was to be 0, then change it to 1. + rm -rf "$test_dir_" || { test $__st = 0 && __st=1; } + fi + exit $__st +} + +# Given a directory name, DIR, if every entry in it that matches *.exe +# contains only the specified bytes (see the case stmt below), then print +# a space-separated list of those names and return 0. Otherwise, don't +# print anything and return 1. Naming constraints apply also to DIR. +find_exe_basenames_ () +{ + feb_dir_=$1 + feb_fail_=0 + feb_result_= + feb_sp_= + for feb_file_ in $feb_dir_/*.exe; do + # If there was no *.exe file, or there existed a file named "*.exe" that + # was deleted between the above glob expansion and the existence test + # below, just skip it. + test "x$feb_file_" = "x$feb_dir_/*.exe" && test ! -f "$feb_file_" \ + && continue + # Exempt [.exe, since we can't create a function by that name, yet + # we can't invoke [ by PATH search anyways due to shell builtins. + test "x$feb_file_" = "x$feb_dir_/[.exe" && continue + case $feb_file_ in + *[!-a-zA-Z/0-9_.+]*) feb_fail_=1; break;; + *) # Remove leading file name components as well as the .exe suffix. + feb_file_=${feb_file_##*/} + feb_file_=${feb_file_%.exe} + feb_result_="$feb_result_$feb_sp_$feb_file_";; + esac + feb_sp_=' ' + done + test $feb_fail_ = 0 && printf %s "$feb_result_" + return $feb_fail_ +} + +# Consider the files in directory, $1. +# For each file name of the form PROG.exe, create an alias named +# PROG that simply invokes PROG.exe, then return 0. If any selected +# file name or the directory name, $1, contains an unexpected character, +# define no alias and return 1. +create_exe_shims_ () +{ + case $EXEEXT in + '') return 0 ;; + .exe) ;; + *) echo "$0: unexpected \$EXEEXT value: $EXEEXT" 1>&2; return 1 ;; + esac + + base_names_=`find_exe_basenames_ $1` \ + || { echo "$0 (exe_shim): skipping directory: $1" 1>&2; return 0; } + + if test -n "$base_names_"; then + for base_ in $base_names_; do + alias "$base_"="$base_$EXEEXT" + done + fi + + return 0 +} + +# Use this function to prepend to PATH an absolute name for each +# specified, possibly-$initial_cwd_-relative, directory. +path_prepend_ () +{ + while test $# != 0; do + path_dir_=$1 + case $path_dir_ in + '') fail_ "invalid path dir: '$1'";; + /*) abs_path_dir_=$path_dir_;; + *) abs_path_dir_=$initial_cwd_/$path_dir_;; + esac + case $abs_path_dir_ in + *:*) fail_ "invalid path dir: '$abs_path_dir_'";; + esac + PATH="$abs_path_dir_:$PATH" + + # Create an alias, FOO, for each FOO.exe in this directory. + create_exe_shims_ "$abs_path_dir_" \ + || fail_ "something failed (above): $abs_path_dir_" + shift + done + export PATH +} + +setup_ () +{ + if test "$VERBOSE" = yes; then + # Test whether set -x may cause the selected shell to corrupt an + # application's stderr. Many do, including zsh-4.3.10 and the /bin/sh + # from SunOS 5.11, OpenBSD 4.7 and Irix 5.x and 6.5. + # If enabling verbose output this way would cause trouble, simply + # issue a warning and refrain. + if $gl_set_x_corrupts_stderr_; then + warn_ "using SHELL=$SHELL with 'set -x' corrupts stderr" + else + set -x + fi + fi + + initial_cwd_=$PWD + + pfx_=`testdir_prefix_` + test_dir_=`mktempd_ "$initial_cwd_" "$pfx_-$ME_.XXXX"` \ + || fail_ "failed to create temporary directory in $initial_cwd_" + cd "$test_dir_" || fail_ "failed to cd to temporary directory" + + # As autoconf-generated configure scripts do, ensure that IFS + # is defined initially, so that saving and restoring $IFS works. + gl_init_sh_nl_=' +' + IFS=" "" $gl_init_sh_nl_" + + # This trap statement, along with a trap on 0 below, ensure that the + # temporary directory, $test_dir_, is removed upon exit as well as + # upon receipt of any of the listed signals. + for sig_ in 1 2 3 13 15; do + eval "trap 'Exit $(expr $sig_ + 128)' $sig_" + done +} + +# Create a temporary directory, much like mktemp -d does. +# Written by Jim Meyering. +# +# Usage: mktempd_ /tmp phoey.XXXXXXXXXX +# +# First, try to use the mktemp program. +# Failing that, we'll roll our own mktemp-like function: +# - try to get random bytes from /dev/urandom +# - failing that, generate output from a combination of quickly-varying +# sources and gzip. Ignore non-varying gzip header, and extract +# "random" bits from there. +# - given those bits, map to file-name bytes using tr, and try to create +# the desired directory. +# - make only $MAX_TRIES_ attempts + +# Helper function. Print $N pseudo-random bytes from a-zA-Z0-9. +rand_bytes_ () +{ + n_=$1 + + # Maybe try openssl rand -base64 $n_prime_|tr '+/=\012' abcd first? + # But if they have openssl, they probably have mktemp, too. + + chars_=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 + dev_rand_=/dev/urandom + if test -r "$dev_rand_"; then + # Note: 256-length($chars_) == 194; 3 copies of $chars_ is 186 + 8 = 194. + dd ibs=$n_ count=1 if=$dev_rand_ 2>/dev/null \ + | LC_ALL=C tr -c $chars_ 01234567$chars_$chars_$chars_ + return + fi + + n_plus_50_=`expr $n_ + 50` + cmds_='date; date +%N; free; who -a; w; ps auxww; ps ef; netstat -n' + data_=` (eval "$cmds_") 2>&1 | gzip ` + + # Ensure that $data_ has length at least 50+$n_ + while :; do + len_=`echo "$data_"|wc -c` + test $n_plus_50_ -le $len_ && break; + data_=` (echo "$data_"; eval "$cmds_") 2>&1 | gzip ` + done + + echo "$data_" \ + | dd bs=1 skip=50 count=$n_ 2>/dev/null \ + | LC_ALL=C tr -c $chars_ 01234567$chars_$chars_$chars_ +} + +mktempd_ () +{ + case $# in + 2);; + *) fail_ "Usage: mktempd_ DIR TEMPLATE";; + esac + + destdir_=$1 + template_=$2 + + MAX_TRIES_=4 + + # Disallow any trailing slash on specified destdir: + # it would subvert the post-mktemp "case"-based destdir test. + case $destdir_ in + / | //) destdir_slash_=$destdir;; + */) fail_ "invalid destination dir: remove trailing slash(es)";; + *) destdir_slash_=$destdir_/;; + esac + + case $template_ in + *XXXX) ;; + *) fail_ \ + "invalid template: $template_ (must have a suffix of at least 4 X's)";; + esac + + # First, try to use mktemp. + d=`unset TMPDIR; { mktemp -d -t -p "$destdir_" "$template_"; } 2>/dev/null` && + + # The resulting name must be in the specified directory. + case $d in "$destdir_slash_"*) :;; *) false;; esac && + + # It must have created the directory. + test -d "$d" && + + # It must have 0700 permissions. Handle sticky "S" bits. + perms=`ls -dgo "$d" 2>/dev/null` && + case $perms in drwx--[-S]---*) :;; *) false;; esac && { + echo "$d" + return + } + + # If we reach this point, we'll have to create a directory manually. + + # Get a copy of the template without its suffix of X's. + base_template_=`echo "$template_"|sed 's/XX*$//'` + + # Calculate how many X's we've just removed. + template_length_=`echo "$template_" | wc -c` + nx_=`echo "$base_template_" | wc -c` + nx_=`expr $template_length_ - $nx_` + + err_= + i_=1 + while :; do + X_=`rand_bytes_ $nx_` + candidate_dir_="$destdir_slash_$base_template_$X_" + err_=`mkdir -m 0700 "$candidate_dir_" 2>&1` \ + && { echo "$candidate_dir_"; return; } + test $MAX_TRIES_ -le $i_ && break; + i_=`expr $i_ + 1` + done + fail_ "$err_" +} + +# If you want to override the testdir_prefix_ function, +# or to add more utility functions, use this file. +test -f "$srcdir/init.cfg" \ + && . "$srcdir/init.cfg" + +setup_ "$@" +# This trap is here, rather than in the setup_ function, because some +# shells run the exit trap at shell function exit, rather than script exit. +trap remove_tmp_ 0 From 4802dc976b2c9b6f62c2d2932463ec798add3457 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Thu, 28 Sep 2017 19:43:17 +0200 Subject: [PATCH 142/239] maint: Rewrite old NEWS * NEWS: Follow the format used by GNU Coreutils. --- NEWS | 121 +++++++++++++++++++++++++---------------------------------- 1 file changed, 52 insertions(+), 69 deletions(-) diff --git a/NEWS b/NEWS index e53ae23..4d3e9fd 100644 --- a/NEWS +++ b/NEWS @@ -1,106 +1,89 @@ -Historic moments in the life of mcron. -*-text-*- +GNU Mcron NEWS -*- outline -*- - Copyright (C) 2003, 2005, 2006 Dale Mellor +* Noteworthy changes in release ?.? (????-??-??) [?] - Copying and distribution of this file, with or without modification, - are permitted in any medium without royalty provided the copyright - notice and this notice are preserved. +* Noteworthy changes in release 1.0.8 (2014-04-28) [stable] + Man page is now generated with GNU Help2man before installation and + distributed in the tarball. -Please send bug reports to bug-mcron@gnu.org. +* Noteworthy changes in release 1.0.7 (2012-02-04) [stable] + Mcron is now compatible with Guile 2.0. -Saturday, 4th February 2012 + FreeDesktop.org's standard user configuration directories are now used to + find the user script files. - Received a suggestion from Antono Vasiljev to look in FreeDesktop.org's - standard user configuration directories for user script files. This is - implemented in the GIT repository. +* Noteworthy changes in release 1.0.6 (2010-06-20) [stable] + The copyright notices are now standardized on all auxiliary files. This + follows the example set by the GNU hello program. -Sunday, 20th June 2010 + immutable end texts from the texinfo document are now removed, to + accomodate with Debian requirements. - Standardized the copyright notices on all auxiliary files (including this - one!) according to the example set by the GNU hello program. Removed - immutable end texts from the texinfo document. These changes are required - for Debianization. Released as version 1.0.6. +* Noteworthy changes in release 1.0.5 (2010-06-13) [stable] + Some technical changes to the build system has been made to help the + distribution to Debian. -Sunday, 13th June 2010 + The Git repository has been completely re-hashed, and now represents a + complete and faithful history of the package's development since its + inception. - Made some technical changes to the build system to aid Debianization. - Released without announcement as version 1.0.5. +* Noteworthy changes in release 1.0.4 (2008-02-21) [stable] - The GIT repository has been completely re-hashed, and now represents a - complete and faithful history of the package's development since its - inception. - + The source code is now held in a Git repository, which can be checked-out at + . -Thursday, 21st February 2008 + The code is now covered by the GPLv3 license. - The source code is now held in a GIT repository, at - git://git.savannah.gnu.org/mcron.git. +* Noteworthy changes in release 1.0.3 (2006-04-16) [stable] - Released version 1.0.4, under the new GPLv3 license, after some prodding by - Karl Berry. + daylight savings time shifts are now properly handled + Parsing Vixie-style input files has been improved. -Sunday, 16th April 2006 - Released version 1.0.3. Incorporated many coding suggestions by Sergey - Poznyakoff, which makes the program work with daylight savings time shifts, - fixes a bug in parsing Vixie-style input files, allows a user the - opportunity to correct a crontab entry instead of just wiping out the file. - Made it work with Guile 1.8. Updated the manual with GFDL and some minor - suggestions from Karl Berry. + Crontab entries can now be corrected instead of just wiping out the file. + Mcron is now compatible with Guile 1.8. -Monday, 2nd January 2006 - Released version 1.0.2. + The manual is now licensed under the GNU Free Documentation License (GFDL) +* Noteworthy changes in release 1.0.2 (2006-01-02) [stable] -Saturday, 15th May 2004 - Set up Savannah and the mailing lists so that we are now homed properly at - gnu.org. Released version 1.0.1 to reflect this, with CVS tag release_1-0-1 - (no branch). Hopefully we will now get some feedback! +* Noteworthy changes in release 1.0.1 (2004-05-15) [stable] + The mailing list has been set-up. -Friday, 12th December 2003 - Released version 1.0.0 through rdmp.org. No CVS tag has been created. +* Noteworthy changes in release 1.0 (2003-12-12) [stable] + Mcron is now officially a GNU program. -Tuesday, 2nd December 2003 - Mcron is now officially a GNU program. Unfortunately Savannah, the - development environment, has been mauled so an immediate GNU release is not - likely. No CVS tag has been created. +* Noteworthy changes in release 0.99.3 (2003-08-05) [stable] + The code is now splitted into modules. -Tuesday, 5th August 2003 - Released version 0.99.3. The CVS tag will be release_0-99-3 (no branch). +* Noteworthy changes in release 0.99.2 (2003-07-20) [stable] + The implementation is now really 100% Vixie compatible. -Sunday, 3rd August 2003 - Broken the code into modules (which is not the same as saying the code is - broken ;-) ). + Some Guile limitations such as the absence of POSIX threads and signals has + been worked around. +* Noteworthy changes in release 0.99.1 (2003-07-05) [stable] -Sunday, 20th July 2003 - Released version 0.99.2. (Now fully functional). The CVS tag is - release_0-99-2 (no branch). + Installation of cron and crontab is now disabled by default (suspect problems + with Guile internals are preventing these from working properly). + The project is now managed on Savannah. A CVS repository and web page have been + created. -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. +======================================================================== +Copyright © 2003, 2005, 2006 Dale Mellor +Copyright © 2017 Mathieu Lirzin -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 - working properly). The CVS tag is release_0-99-1 (no branch has been - created for it). - - -Friday, 4th July 2003 - We have been accepted as a Savannah project. A CVS repository and web home - page have been created. We're still waiting for acceptance as a GNU - project. +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. From a0b896c9d55f2482e7f7c8c8a222963cecfd2214 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Thu, 28 Sep 2017 23:22:20 +0200 Subject: [PATCH 143/239] maint: Update NEWS * NEWS: Update with changes made since last release. --- NEWS | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/NEWS b/NEWS index 4d3e9fd..3b832d3 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,51 @@ GNU Mcron NEWS -*- outline -*- * Noteworthy changes in release ?.? (????-??-??) [?] +** New features + + The 'job' procedure has now a '#:user' keyword argument which allows + specifying a different user that will run it. + + Additional man pages for 'cron(8)' and 'crontab(1)' are now generated using + GNU Help2man. + +** Bug fixes + + Child process created when executing a job are now properly cleaned even + when execution fails by using 'dynamic-wind' construct. + +** Improvements + + GNU Guile 2.2 is now supported. + + Some procedures are now written using functional style and include a + docstring. 'def-macro' usages are now replaced with hygienic macros. + + Compilation is now done using a non-recursive Makefile, supports out of tree + builds, and use silent rules by default. + + Guile object files creation don't rely on auto-compilation anymore and are + installed in 'site-ccache' directory. + + Jobs are now internally represented using SRFI-9 records instead of vectors. + + Changelog are generated from Git logs when generating the tarball using + Gnulib gitlog-to-changelog script. + + A test suite is now available and can be run with 'make check'. + +** Changes in behavior + + The "--enable-debug" configure variable has been removed and replaced with + MCRON_DEBUG environment variable. + + The "--disable-multi-user" configure variable is now used to not build and + install the 'cron' and 'crontab' programs. It has replaced the + "--enable-no-vixie-clobber" which had similar effect. + + (mcron core) module is now deprecated and has been superseeded by + (mcron base). + * Noteworthy changes in release 1.0.8 (2014-04-28) [stable] Man page is now generated with GNU Help2man before installation and From dc5a7a500e4628b28597dc128151807c7ab949c6 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Thu, 28 Sep 2017 23:30:02 +0200 Subject: [PATCH 144/239] =?UTF-8?q?maint:=20Add=20Ludovic=20Court=C3=A8s?= =?UTF-8?q?=20to=20the=20authors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * AUTHORS: Add Ludovic Courtès. --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index ed0888b..fe01d34 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,3 +1,4 @@ Dale Mellor Mathieu Lirzin Sergey Poznyakoff +Ludovic Courtès From 319a1dbe4e6147cfe3e474dc03ae281b84a8765c Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Fri, 29 Sep 2017 16:52:48 +0200 Subject: [PATCH 145/239] maint: Replace "README--git" with "HACKING" * README--git: Delete. * HACKING: New file documenting how to contribute to Mcron. * Makefile.am (EXTRA_DIST): Distribute it. --- HACKING | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++ Makefile.am | 1 + README--git | 20 -------------- 3 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 HACKING delete mode 100644 README--git diff --git a/HACKING b/HACKING new file mode 100644 index 0000000..a9e9f5a --- /dev/null +++ b/HACKING @@ -0,0 +1,76 @@ +These notes intend to help people working on the checked-out sources. +These requirements do not apply when building from a distribution tarball. + +* First Git checkout + +You can get a copy of the source repository like this: + + $ git clone git://git.sv.gnu.org/mcron + $ cd mcron + +The next step is to get and check other files needed to build, which are +extracted from other source packages: + + $ ./bootstrap + +And there you are! Just + + $ ./configure + $ make + +At this point, there should be no difference between your local copy, and the +Git master copy: + + $ git diff + +should output no difference. + +Enjoy! + +* Submitting patches + +If you develop a fix or a new feature, please send it to the appropriate +bug-reporting address as reported by the --help option of each program. One +way to do this is to use vc-dwim ), as +follows. + + Run the command "vc-dwim --help", copy its definition of the + "git-changelog-symlink-init" function into your shell, and then run this + function at the top-level directory of the package. + + Edit the (empty) ChangeLog file that this command creates, creating a + properly-formatted entry according to the GNU coding standards + . + + Make your changes. + + Run the command "vc-dwim" and make sure its output (the diff of all your + changes) looks good. + + Run "vc-dwim --commit". + + Run the command "git format-patch --stdout -1", and email its output in, + using the output's subject line. + +----- + +Copyright © 2002-2017 Free Software Foundation, Inc. +Copyright © 2017 Mathieu Lirzin + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Local Variables: +mode: outline +fill-column: 78 +End: diff --git a/Makefile.am b/Makefile.am index 84cbf23..9972c5c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -163,6 +163,7 @@ gen-ChangeLog: EXTRA_DIST = \ bootstrap \ build-aux/guix.scm \ + HACKING \ tests/init.sh \ $(TESTS) diff --git a/README--git b/README--git deleted file mode 100644 index 0b24ded..0000000 --- a/README--git +++ /dev/null @@ -1,20 +0,0 @@ -GNU mcron --- README--git -*-text-*- - - Copyright (C) 2012, 2014 Dale Mellor - Copyright (C) 2015, 2016 Mathieu Lirzin - - Copying and distribution of this file, with or without modification, - are permitted in any medium without royalty provided the copyright - notice and this notice are preserved. - - -If you have pulled mcron from the GIT repository, these are the steps you will -need to take to build it the first time: - -1) autoreconf -vfi -2) ./configure --prefix={wherever} -3) make install - - -After that it should just be a simple matter of typing `make install' when you -want to build a version with changes in it. From 266bcf840588ac895413c926afc20b75a1ffb7b4 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Fri, 29 Sep 2017 17:58:49 +0200 Subject: [PATCH 146/239] maint: Remove old mailing-lists from README * README: Remove non-existing mailing-lists. --- README | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README b/README index 057f962..542c5d3 100644 --- a/README +++ b/README @@ -60,10 +60,7 @@ programs are included here. Features which might be implemented sometime sooner or later are noted in the TODO file. -Please send all other bug reports to bug-mcron@gnu.org. Other mailing lists you -could subscribe to are help-mcron@gnu.org (for help and advice from the -community, including the author) and info-mcron@gnu.org (for news as it -happens). +Please send all other bug reports to bug-mcron@gnu.org. Mcron is free software. See the file COPYING for copying conditions. From b80020ef782921df147b957c4041f4b61d61c673 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Thu, 27 Apr 2017 15:27:00 +0200 Subject: [PATCH 147/239] crontab: Extract procedures from 'main' * src/mcron/scripts/crontab.scm (in-access-file?) (hit-server): New procedures. --- src/mcron/scripts/crontab.scm | 69 +++++++++++++++++------------------ 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/src/mcron/scripts/crontab.scm b/src/mcron/scripts/crontab.scm index 502fec6..abc3d7b 100644 --- a/src/mcron/scripts/crontab.scm +++ b/src/mcron/scripts/crontab.scm @@ -42,6 +42,36 @@ (version (single-char #\v) (value #f)) (help (single-char #\h) (value #f)))) +(define (hit-server user-name) + "Tell the running cron daemon that the user corresponding to +USER-NAME has modified his crontab. USER-NAME is written to the +'/var/cron/socket' UNIX socket." + (catch #t + (lambda () + (let ((socket (socket AF_UNIX SOCK_STREAM 0))) + (connect socket AF_UNIX config-socket-file) + (display user-name socket) + (close socket))) + (lambda (key . args) + (display "Warning: a cron daemon is not running.\n")))) + +(define (in-access-file? file name) + "Scan FILE which should contain one user name per line (such as +'/var/cron/allow' and '/var/cron/deny'). Return #t if NAME is in there, and +#f otherwise. if FILE cannot be opened, a error is signaled." + (catch #t + (lambda () + (with-input-from-file file + (lambda () + (let loop ((input (read-line))) + (cond ((eof-object? input) + #f) + ((string=? input name) + #t) + (else + (loop (read-line)))))))) + (const '()))) + ;;; ;;; Entry point. @@ -57,41 +87,10 @@ ((option-ref opts 'version #f) (show-version "crontab") (exit 0))) - (let ((hit-server - (λ (user-name) - ;; Procedure to communicate with running cron daemon that a user - ;; has modified his crontab. The user name is written to the - ;; /var/cron/socket UNIX socket. - (catch #t - (λ () - (let ((socket (socket AF_UNIX SOCK_STREAM 0))) - (connect socket AF_UNIX config-socket-file) - (display user-name socket) - (close socket))) - (λ (key . args) - (display "Warning: a cron daemon is not running.\n"))))) - - ;; Procedure to scan a file containing one user name per line (such - ;; as /var/cron/allow and /var/cron/deny), and determine if the - ;; given name is in there. The procedure returns #t, #f, or '() if - ;; the file does not exist. - (in-access-file? - (λ (file name) - (catch #t - (λ () - (with-input-from-file file - (λ () - (let loop ((input (read-line))) - (if (eof-object? input) - #f - (if (string=? input name) - #t - (loop (read-line)))))))) - (λ (key . args) '())))) - - ;; This program should have been installed SUID root. Here we get - ;; the passwd entry for the real user who is running this program. - (crontab-real-user (passwd:name (getpw (getuid))))) + (let ((crontab-real-user + ;; This program should have been installed SUID root. Here we get + ;; the passwd entry for the real user who is running this program. + (passwd:name (getpw (getuid))))) ;; If the real user is not allowed to use crontab due to the ;; /var/cron/allow and/or /var/cron/deny files, bomb out now. From 5f83aef90f0b5a3bef3baee48bc6f6cdf452155d Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Thu, 19 Oct 2017 23:22:14 +0200 Subject: [PATCH 148/239] base: Add 'display-schedule' procedure This procedure is a more generic and less coupled version of 'get-schedule' which has been kept for backward compatibility and deprecated. * src/mcron/base.scm (display-schedule): New procedure. (get-schedule): Move to ... * src/mcron/core.scm: ... here. * src/mcron/scripts/cron.scm (main): Use 'display-schedule'. * src/mcron/scripts/mcron.scm (main): Likewise. * doc/mcron.texi (The base module): Document it. --- doc/mcron.texi | 7 ++++-- src/mcron/base.scm | 46 +++++++++++++++---------------------- src/mcron/core.scm | 7 +++++- src/mcron/scripts/cron.scm | 2 +- src/mcron/scripts/mcron.scm | 2 +- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/doc/mcron.texi b/doc/mcron.texi index 70e9d98..04f92bd 100644 --- a/doc/mcron.texi +++ b/doc/mcron.texi @@ -1233,9 +1233,12 @@ entry. All jobs on the current job list that are scheduled to be run under this personality are removed from the job list. @end deffn -@deffn{Scheme procedure} get-schedule count +@deffn{Scheme procedure} display-schedule @var{count} [@var{port}] @cindex schedule of jobs -The argument @var{count} should be an integer value giving the number +This procedure is used to display a textual list of the next COUNT jobs +to run. + +The argument @var{count} must be an integer value giving the number of time-points in the future to report that jobs will run as. Note that this procedure is disruptive; if @code{run-job-loop} is called after this procedure, the first job to run will be the one after the diff --git a/src/mcron/base.scm b/src/mcron/base.scm index 942ebf2..3528236 100644 --- a/src/mcron/base.scm +++ b/src/mcron/base.scm @@ -26,7 +26,7 @@ #:use-module (srfi srfi-9) #:export (add-job remove-user-jobs - get-schedule + display-schedule run-job-loop ;; Deprecated and undocumented procedures. use-system-job-list @@ -136,35 +136,27 @@ recurse the list." (else (loop rest next-time next-jobs)))))))) -;; Create a string containing a textual list of the next count jobs to run. -;; -;; Enter a loop of displaying the next set of jobs to run, artificially -;; forwarding the time to the next time point (instead of waiting for it to -;; occur as we would do in a normal run of mcron), and recurse around the loop -;; count times. -;; -;; Note that this has the effect of mutating the job timings. Thus the program -;; must exit after calling this function; the internal data state will be left -;; unusable. - -(define (get-schedule count) - (with-output-to-string - (lambda () - (do ((count count (- count 1))) - ((eqv? count 0)) - (and-let* - ((next-jobs (find-next-jobs)) - (time (car next-jobs)) - (date-string (strftime "%c %z\n" (localtime time)))) +(define* (display-schedule count #:optional (port (current-output-port))) + "Display on PORT a textual list of the next COUNT jobs to run. This +simulates the run of the job loop to display the resquested information. +Since calling this procedure has the effect of mutating the job timings, the +program must exit after. Otherwise the internal data state will be left +unusable." + (unless (<= count 0) + (match (find-next-jobs) + ((#f . jobs) + #f) + ((time . jobs) + (let ((date-string (strftime "%c %z\n" (localtime time)))) (for-each (lambda (job) - (display date-string) - (display (job:displayable job)) - (newline)(newline) + (display date-string port) + (display (job:displayable job) port) + (newline port) + (newline port) (job:next-time-set! job ((job:next-time-function job) (job:next-time job)))) - (cdr next-jobs))))))) - - + jobs)))) + (display-schedule (- count 1) port))) ;; For proper housekeeping, it is necessary to keep a record of the number of ;; child processes we fork off to run the jobs. diff --git a/src/mcron/core.scm b/src/mcron/core.scm index fcf96af..987881d 100644 --- a/src/mcron/core.scm +++ b/src/mcron/core.scm @@ -20,9 +20,10 @@ (define-module (mcron core) #:use-module (mcron base) + #:export (;; Deprecated + get-schedule) #:re-export (add-job remove-user-jobs - get-schedule run-job-loop clear-environment-mods append-environment-mods @@ -30,3 +31,7 @@ use-system-job-list use-user-job-list clear-system-jobs)) + +(define (get-schedule count) + (with-output-to-string + (lambda () (display-schedule count)))) diff --git a/src/mcron/scripts/cron.scm b/src/mcron/scripts/cron.scm index d043d79..5052c32 100644 --- a/src/mcron/scripts/cron.scm +++ b/src/mcron/scripts/cron.scm @@ -157,7 +157,7 @@ option.\n") (option-ref opts 'noetc #f)) (cond ((option-ref opts 'schedule #f) ;display jobs schedule => (λ (count) - (display (get-schedule (max 1 (string->number count)))) + (display-schedule (max 1 (string->number count))) (exit 0))) (else (case (primitive-fork) ;run the daemon ((0) diff --git a/src/mcron/scripts/mcron.scm b/src/mcron/scripts/mcron.scm index 588734b..afb380f 100644 --- a/src/mcron/scripts/mcron.scm +++ b/src/mcron/scripts/mcron.scm @@ -83,7 +83,7 @@ $XDG_CONFIG_HOME is not defined uses ~/.config/cron instead)." (cond ((assq-ref opts 'schedule) ;display jobs schedule => (λ (count) - (display (get-schedule (max 1 count))) + (display-schedule (max 1 count)) (exit 0))) ((assq-ref opts 'daemon) ;run mcron as a daemon (case (primitive-fork) From 2b9b54b72938144320e1a1285b011182a3c52ac4 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Thu, 19 Oct 2017 23:58:57 +0200 Subject: [PATCH 149/239] tests: Add 'schedule.sh' * tests/schedule.sh: New test. * Makefile.am (TESTS): Add it. * src/mcron/job-specifier.scm (configuration-time): Use SOURCE_DATE_EPOCH for reproducible tests. --- Makefile.am | 1 + src/mcron/job-specifier.scm | 5 +- tests/schedule.sh | 123 ++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 tests/schedule.sh diff --git a/Makefile.am b/Makefile.am index 9972c5c..cb43143 100644 --- a/Makefile.am +++ b/Makefile.am @@ -135,6 +135,7 @@ SCM_LOG_DRIVER = \ TESTS = \ tests/basic.sh \ + tests/schedule.sh \ tests/environment.scm \ tests/job-specifier.scm diff --git a/src/mcron/job-specifier.scm b/src/mcron/job-specifier.scm index 30c770a..401e4d0 100644 --- a/src/mcron/job-specifier.scm +++ b/src/mcron/job-specifier.scm @@ -187,7 +187,10 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." ;; the job actually runs. (define configuration-user (getpw (getuid))) -(define configuration-time (current-time)) + +(define configuration-time + ;; Use SOURCE_DATE_EPOCH environment variable to support reproducible tests. + (if (getenv "SOURCE_DATE_EPOCH") 0 (current-time))) (define (set-configuration-user user) (set! configuration-user (if (or (string? user) diff --git a/tests/schedule.sh b/tests/schedule.sh new file mode 100644 index 0000000..ad267c4 --- /dev/null +++ b/tests/schedule.sh @@ -0,0 +1,123 @@ +# schedule.sh -- Check mcron schedule output +# Copyright © 2017 Mathieu Lirzin +# +# This file is part of GNU Mcron. +# +# GNU Mcron is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNU Mcron is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Mcron. If not, see . + +source "${srcdir}/tests/init.sh" + +SOURCE_DATE_EPOCH=1 +export SOURCE_DATE_EPOCH + +# Use current working directory to store mcron files +XDG_CONFIG_HOME=`pwd` +export XDG_CONFIG_HOME + +mkdir cron +cat > cron/foo.guile < cron/bar.guile < expected < output +diff expected output || fail_ "schedule output is not correct" + +Exit 0 From d1fdb14a8a0bc180668ba12b9a6ff97744edce8f Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 17 Mar 2018 16:32:25 +0100 Subject: [PATCH 150/239] build: Programs are not implicitly depending on libraries Before that change, it was possible for 'make' to try linking programs before 'src/libmcron.a' was built. * Makefile.am (bin_mcron_DEPENDENCIES, bin_cron_DEPENDENCIES) (bin_crontab_DEPENDENCIES): Add '$(noinst_LIBRARIES)'. --- Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index cb43143..1e953c6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -39,13 +39,13 @@ AM_CFLAGS = @GUILE_CFLAGS@ LDADD = @GUILE_LIBS@ src/libmcron.a bin_mcron_SOURCES = src/mcron.c -bin_mcron_DEPENDENCIES = $(compiled_modules) +bin_mcron_DEPENDENCIES = $(compiled_modules) $(noinst_LIBRARIES) bin_cron_SOURCES = src/cron.c -bin_cron_DEPENDENCIES = $(compiled_modules) +bin_cron_DEPENDENCIES = $(compiled_modules) $(noinst_LIBRARIES) bin_crontab_SOURCES = src/crontab.c -bin_crontab_DEPENDENCIES = $(compiled_modules) +bin_crontab_DEPENDENCIES = $(compiled_modules) $(noinst_LIBRARIES) # wrapper to be used in the build environment and for running tests. noinst_SCRIPTS = pre-inst-env From b7640b81edaa0ebf2b4d97b2ba02c59dcc31f4a6 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 18 Mar 2018 21:58:41 +0100 Subject: [PATCH 151/239] maint: Include maintainer scripts from Gnulib * build-aux/announce-gen: New script. * build-aux/do-release-commit-and-tag: Likewise. * build-aux/gnu-web-doc-update: Likewise. * build-aux/gnupload: Likewise. --- build-aux/announce-gen | 557 ++++++++++++++++++++++++++++ build-aux/do-release-commit-and-tag | 179 +++++++++ build-aux/gnu-web-doc-update | 210 +++++++++++ build-aux/gnupload | 440 ++++++++++++++++++++++ 4 files changed, 1386 insertions(+) create mode 100755 build-aux/announce-gen create mode 100755 build-aux/do-release-commit-and-tag create mode 100755 build-aux/gnu-web-doc-update create mode 100755 build-aux/gnupload diff --git a/build-aux/announce-gen b/build-aux/announce-gen new file mode 100755 index 0000000..eeb9071 --- /dev/null +++ b/build-aux/announce-gen @@ -0,0 +1,557 @@ +eval '(exit $?0)' && eval 'exec perl -wS "$0" "$@"' + & eval 'exec perl -wS "$0" $argv:q' + if 0; +# Generate a release announcement message. + +my $VERSION = '2018-03-07 03:46'; # UTC +# The definition above must lie within the first 8 lines in order +# for the Emacs time-stamp write hook (at end) to update it. +# If you change this file with Emacs, please let the write hook +# do its job. Otherwise, update this string manually. + +# Copyright (C) 2002-2018 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Written by Jim Meyering + +use strict; + +use Getopt::Long; +use POSIX qw(strftime); + +(my $ME = $0) =~ s|.*/||; + +my %valid_release_types = map {$_ => 1} qw (alpha beta stable); +my @archive_suffixes = ('tar.gz', 'tar.bz2', 'tar.lzma', 'tar.xz'); +my %digest_classes = + ( + 'md5' => (eval { require Digest::MD5; } and 'Digest::MD5'), + 'sha1' => ((eval { require Digest::SHA; } and 'Digest::SHA') + or (eval { require Digest::SHA1; } and 'Digest::SHA1')) + ); +my $srcdir = '.'; + +sub usage ($) +{ + my ($exit_code) = @_; + my $STREAM = ($exit_code == 0 ? *STDOUT : *STDERR); + if ($exit_code != 0) + { + print $STREAM "Try '$ME --help' for more information.\n"; + } + else + { + my @types = sort keys %valid_release_types; + print $STREAM < = C + +Compute the sizes of the C<@file> and return them as a hash. Return +C if one of the computation failed. + +=cut + +sub sizes (@) +{ + my (@file) = @_; + + my $fail = 0; + my %res; + foreach my $f (@file) + { + my $cmd = "du -h $f"; + my $t = `$cmd`; + # FIXME-someday: give a better diagnostic, a la $PROCESS_STATUS + $@ + and (warn "command failed: '$cmd'\n"), $fail = 1; + chomp $t; + $t =~ s/^\s*([\d.]+[MkK]).*/${1}B/; + $res{$f} = $t; + } + return $fail ? undef : %res; +} + +=item C dedicated to the list of <@file>, which +sizes are stored in C<%size>, and which are available from the C<@url>. + +=cut + +sub print_locations ($\@\%@) +{ + my ($title, $url, $size, @file) = @_; + print "Here are the $title:\n"; + foreach my $url (@{$url}) + { + for my $file (@file) + { + print " $url/$file"; + print " (", $$size{$file}, ")" + if exists $$size{$file}; + print "\n"; + } + } + print "\n"; +} + +=item C. + +=cut + +sub print_checksums (@) +{ + my (@file) = @_; + + print "Here are the MD5 and SHA1 checksums:\n"; + print "\n"; + + foreach my $meth (qw (md5 sha1)) + { + my $class = $digest_classes{$meth} or next; + foreach my $f (@file) + { + open IN, '<', $f + or die "$ME: $f: cannot open for reading: $!\n"; + binmode IN; + my $dig = $class->new->addfile(*IN)->hexdigest; + close IN; + print "$dig $f\n"; + } + } + print "\n"; +} + +=item C addressing changes +between versions C<$prev_version> and C<$curr_version>. + +=cut + +sub print_news_deltas ($$$) +{ + my ($news_file, $prev_version, $curr_version) = @_; + + my $news_name = $news_file; + $news_name =~ s|^\Q$srcdir\E/||; + + print "\n$news_name\n\n"; + + # Print all lines from $news_file, starting with the first one + # that mentions $curr_version up to but not including + # the first occurrence of $prev_version. + my $in_items; + + my $re_prefix = qr/(?:\* )?(?:Noteworthy c|Major c|C)(?i:hanges)/; + + my $found_news; + open NEWS, '<', $news_file + or die "$ME: $news_file: cannot open for reading: $!\n"; + while (defined (my $line = )) + { + if ( ! $in_items) + { + # Match lines like these: + # * Major changes in release 5.0.1: + # * Noteworthy changes in release 6.6 (2006-11-22) [stable] + $line =~ /^$re_prefix.*(?:[^\d.]|$)\Q$curr_version\E(?:[^\d.]|$)/o + or next; + $in_items = 1; + print $line; + } + else + { + # This regexp must not match version numbers in NEWS items. + # For example, they might well say "introduced in 4.5.5", + # and we don't want that to match. + $line =~ /^$re_prefix.*(?:[^\d.]|$)\Q$prev_version\E(?:[^\d.]|$)/o + and last; + print $line; + $line =~ /\S/ + and $found_news = 1; + } + } + close NEWS; + + $in_items + or die "$ME: $news_file: no matching lines for '$curr_version'\n"; + $found_news + or die "$ME: $news_file: no news item found for '$curr_version'\n"; +} + +sub print_changelog_deltas ($$) +{ + my ($package_name, $prev_version) = @_; + + # Print new ChangeLog entries. + + # First find all CVS-controlled ChangeLog files. + use File::Find; + my @changelog; + find ({wanted => sub {$_ eq 'ChangeLog' && -d 'CVS' + and push @changelog, $File::Find::name}}, + '.'); + + # If there are no ChangeLog files, we're done. + @changelog + or return; + my %changelog = map {$_ => 1} @changelog; + + # Reorder the list of files so that if there are ChangeLog + # files in the specified directories, they're listed first, + # in this order: + my @dir = qw ( . src lib m4 config doc ); + + # A typical @changelog array might look like this: + # ./ChangeLog + # ./po/ChangeLog + # ./m4/ChangeLog + # ./lib/ChangeLog + # ./doc/ChangeLog + # ./config/ChangeLog + my @reordered; + foreach my $d (@dir) + { + my $dot_slash = $d eq '.' ? $d : "./$d"; + my $target = "$dot_slash/ChangeLog"; + delete $changelog{$target} + and push @reordered, $target; + } + + # Append any remaining ChangeLog files. + push @reordered, sort keys %changelog; + + # Remove leading './'. + @reordered = map { s!^\./!!; $_ } @reordered; + + print "\nChangeLog entries:\n\n"; + # print join ("\n", @reordered), "\n"; + + $prev_version =~ s/\./_/g; + my $prev_cvs_tag = "\U$package_name\E-$prev_version"; + + my $cmd = "cvs -n diff -u -r$prev_cvs_tag -rHEAD @reordered"; + open DIFF, '-|', $cmd + or die "$ME: cannot run '$cmd': $!\n"; + # Print two types of lines, making minor changes: + # Lines starting with '+++ ', e.g., + # +++ ChangeLog 22 Feb 2003 16:52:51 -0000 1.247 + # and those starting with '+'. + # Don't print the others. + my $prev_printed_line_empty = 1; + while (defined (my $line = )) + { + if ($line =~ /^\+\+\+ /) + { + my $separator = "*"x70 ."\n"; + $line =~ s///; + $line =~ s/\s.*//; + $prev_printed_line_empty + or print "\n"; + print $separator, $line, $separator; + } + elsif ($line =~ /^\+/) + { + $line =~ s///; + print $line; + $prev_printed_line_empty = ($line =~ /^$/); + } + } + close DIFF; + + # The exit code should be 1. + # Allow in case there are no modified ChangeLog entries. + $? == 256 || $? == 128 + or warn "warning: '$cmd' had unexpected exit code or signal ($?)\n"; +} + +sub get_tool_versions ($$) +{ + my ($tool_list, $gnulib_version) = @_; + @$tool_list + or return (); + + my $fail; + my @tool_version_pair; + foreach my $t (@$tool_list) + { + if ($t eq 'gnulib') + { + push @tool_version_pair, ucfirst $t . ' ' . $gnulib_version; + next; + } + # Assume that the last "word" on the first line of + # 'tool --version' output is the version string. + my ($first_line, undef) = split ("\n", `$t --version`); + if ($first_line =~ /.* (\d[\w.-]+)$/) + { + $t = ucfirst $t; + push @tool_version_pair, "$t $1"; + } + else + { + defined $first_line + and $first_line = ''; + warn "$t: unexpected --version output\n:$first_line"; + $fail = 1; + } + } + + $fail + and exit 1; + + return @tool_version_pair; +} + +{ + # Neutralize the locale, so that, for instance, "du" does not + # issue "1,2" instead of "1.2", what confuses our regexps. + $ENV{LC_ALL} = "C"; + + my $mail_headers; + my $release_type; + my $package_name; + my $prev_version; + my $curr_version; + my $gpg_key_id; + my @url_dir_list; + my @news_file; + my $bootstrap_tools; + my $gnulib_version; + my $print_checksums_p = 1; + + # Reformat the warnings before displaying them. + local $SIG{__WARN__} = sub + { + my ($msg) = @_; + # Warnings from GetOptions. + $msg =~ s/Option (\w)/option --$1/; + warn "$ME: $msg"; + }; + + GetOptions + ( + 'mail-headers=s' => \$mail_headers, + 'release-type=s' => \$release_type, + 'package-name=s' => \$package_name, + 'previous-version=s' => \$prev_version, + 'current-version=s' => \$curr_version, + 'gpg-key-id=s' => \$gpg_key_id, + 'url-directory=s' => \@url_dir_list, + 'news=s' => \@news_file, + 'srcdir=s' => \$srcdir, + 'bootstrap-tools=s' => \$bootstrap_tools, + 'gnulib-version=s' => \$gnulib_version, + 'print-checksums!' => \$print_checksums_p, + 'archive-suffix=s' => \@archive_suffixes, + + help => sub { usage 0 }, + version => sub { print "$ME version $VERSION\n"; exit }, + ) or usage 1; + + my $fail = 0; + # Ensure that each required option is specified. + $release_type + or (warn "release type not specified\n"), $fail = 1; + $package_name + or (warn "package name not specified\n"), $fail = 1; + $prev_version + or (warn "previous version string not specified\n"), $fail = 1; + $curr_version + or (warn "current version string not specified\n"), $fail = 1; + $gpg_key_id + or (warn "GnuPG key ID not specified\n"), $fail = 1; + @url_dir_list + or (warn "URL directory name(s) not specified\n"), $fail = 1; + + my @tool_list = split ',', $bootstrap_tools + if $bootstrap_tools; + + grep (/^gnulib$/, @tool_list) ^ defined $gnulib_version + and (warn "when specifying gnulib as a tool, you must also specify\n" + . "--gnulib-version=V, where V is the result of running git describe\n" + . "in the gnulib source directory.\n"), $fail = 1; + + !$release_type || exists $valid_release_types{$release_type} + or (warn "'$release_type': invalid release type\n"), $fail = 1; + + @ARGV + and (warn "too many arguments:\n", join ("\n", @ARGV), "\n"), + $fail = 1; + $fail + and usage 1; + + my $my_distdir = "$package_name-$curr_version"; + + my $xd = "$package_name-$prev_version-$curr_version.xdelta"; + + my @candidates = map { "$my_distdir.$_" } @archive_suffixes; + my @tarballs = grep {-f $_} @candidates; + + @tarballs + or die "$ME: none of " . join(', ', @candidates) . " were found\n"; + my @sizable = @tarballs; + -f $xd + and push @sizable, $xd; + my %size = sizes (@sizable); + %size + or exit 1; + + my $headers = ''; + if (defined $mail_headers) + { + ($headers = $mail_headers) =~ s/\s+(\S+:)/\n$1/g; + $headers .= "\n"; + } + + # The markup is escaped as <\# so that when this script is sent by + # mail (or part of a diff), Gnus is not triggered. + print < + +FIXME: put comments here + +EOF + + if (@url_dir_list == 1 && @tarballs == 1) + { + # When there's only one tarball and one URL, use a more concise form. + my $m = "$url_dir_list[0]/$tarballs[0]"; + print "Here are the compressed sources and a GPG detached signature[*]:\n" + . " $m\n" + . " $m.sig\n\n"; + } + else + { + print_locations ("compressed sources", @url_dir_list, %size, @tarballs); + -f $xd + and print_locations ("xdelta diffs (useful? if so, " + . "please tell bug-gnulib\@gnu.org)", + @url_dir_list, %size, $xd); + my @sig_files = map { "$_.sig" } @tarballs; + print_locations ("GPG detached signatures[*]", @url_dir_list, %size, + @sig_files); + } + + if ($url_dir_list[0] =~ "gnu\.org") + { + print "Use a mirror for higher download bandwidth:\n"; + if (@tarballs == 1 && $url_dir_list[0] =~ m!https://ftp\.gnu\.org/gnu/!) + { + (my $m = "$url_dir_list[0]/$tarballs[0]") + =~ s!https://ftp\.gnu\.org/gnu/!https://ftpmirror\.gnu\.org/!; + print " $m\n" + . " $m.sig\n\n"; + + } + else + { + print " https://www.gnu.org/order/ftp.html\n\n"; + } + } + + $print_checksums_p + and print_checksums (@sizable); + + print <. + +# Written by Jim Meyering + +ME=$(basename "$0") +warn() { printf '%s: %s\n' "$ME" "$*" >&2; } +die() { warn "$*"; exit 1; } + +help() +{ + cat <. +EOF + exit +} + +version() +{ + year=$(echo "$VERSION" | sed 's/[^0-9].*//') + cat < +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. +EOF + exit +} + +## ------ ## +## Main. ## +## ------ ## + +# Constants. +noteworthy='* Noteworthy changes in release' +noteworthy_stub="$noteworthy ?.? (????-??-??) [?]" + +# Variables. +branch=$(git branch | sed -ne '/^\* /{s///;p;q;}') +builddir=. + +while test $# != 0 +do + # Handle --option=value by splitting apart and putting back on argv. + case $1 in + --*=*) + opt=$(echo "$1" | sed -e 's/=.*//') + val=$(echo "$1" | sed -e 's/[^=]*=//') + shift + set dummy "$opt" "$val" "$@"; shift + ;; + esac + + case $1 in + --help|--version) ${1#--};; + --branch) shift; branch=$1; shift ;; + -C|--builddir) shift; builddir=$1; shift ;; + --*) die "unrecognized option: $1";; + *) break;; + esac +done + +test $# = 2 \ + || die "Usage: $ME [OPTION...] VERSION TYPE" + +ver=$1 +type=$2 + + +## ---------------------- ## +## First, sanity checks. ## +## ---------------------- ## + +# Verify that $ver looks like a version number, and... +echo "$ver"|grep -E '^[0-9][0-9.]*[0-9]$' > /dev/null \ + || die "invalid version: $ver" +prev_ver=$(cat .prev-version) \ + || die 'failed to determine previous version number from .prev-version' + +# Verify that $ver is sensible (> .prev-version). +case $(printf "$prev_ver\n$ver\n"|sort -V -u|tr '\n' ':') in + "$prev_ver:$ver:") ;; + *) die "invalid version: $ver (<= $prev_ver)";; +esac + +case $type in + alpha|beta|stable) ;; + *) die "invalid release type: $type";; +esac + +# No local modifications allowed. +case $(git diff-index --name-only HEAD) in + '') ;; + *) die 'this tree is dirty; commit your changes first';; +esac + +# Ensure the current branch name is correct: +curr_br=$(git rev-parse --symbolic-full-name HEAD) +test "$curr_br" = "refs/heads/$branch" || die not on branch $branch + +# Extract package name from Makefile. +Makefile=$builddir/Makefile +pkg=$(sed -n 's/^PACKAGE = \(.*\)/\1/p' "$Makefile") \ + || die "failed to determine package name from $Makefile" + +# Check that line 3 of NEWS is the stub line about to be replaced. +test "$(sed -n 3p NEWS)" = "$noteworthy_stub" \ + || die "line 3 of NEWS must be exactly '$noteworthy_stub'" + +## --------------- ## +## Then, changes. ## +## --------------- ## + +# Update NEWS to have today's date, plus desired version number and $type. +perl -MPOSIX -ni -e 'my $today = strftime "%F", localtime time;' \ + -e 'my ($type, $ver) = qw('"$type $ver"');' \ + -e 'my $pfx = "'"$noteworthy"'";' \ + -e 'print $.==3 ? "$pfx $ver ($today) [$type]\n" : $_' \ + NEWS || die 'failed to update NEWS' + +printf "version $ver\n\n* NEWS: Record release date.\n" \ + | git commit -F - -a || die 'git commit failed' +git tag -s -m "$pkg $ver" v$ver HEAD || die 'git tag failed' + +# Local variables: +# indent-tabs-mode: nil +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "VERSION=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: " # UTC" +# End: diff --git a/build-aux/gnu-web-doc-update b/build-aux/gnu-web-doc-update new file mode 100755 index 0000000..356c561 --- /dev/null +++ b/build-aux/gnu-web-doc-update @@ -0,0 +1,210 @@ +#!/bin/sh +# Run this after each non-alpha release, to update the web documentation at +# https://www.gnu.org/software/$pkg/manual/ + +VERSION=2018-03-07.03; # UTC + +# Copyright (C) 2009-2018 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +ME=$(basename "$0") +warn() { printf '%s: %s\n' "$ME" "$*" >&2; } +die() { warn "$*"; exit 1; } + +help() +{ + cat <. +EOF + exit +} + +version() +{ + year=$(echo "$VERSION" | sed 's/[^0-9].*//') + cat < +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. +EOF + exit +} + +# find_tool ENVVAR NAMES... +# ------------------------- +# Search for a required program. Use the value of ENVVAR, if set, +# otherwise find the first of the NAMES that can be run (i.e., +# supports --version). If found, set ENVVAR to the program name, +# die otherwise. +# +# FIXME: code duplication, see also bootstrap. +find_tool () +{ + find_tool_envvar=$1 + shift + find_tool_names=$@ + eval "find_tool_res=\$$find_tool_envvar" + if test x"$find_tool_res" = x; then + for i + do + if ($i --version /dev/null 2>&1; then + find_tool_res=$i + break + fi + done + else + find_tool_error_prefix="\$$find_tool_envvar: " + fi + test x"$find_tool_res" != x \ + || die "one of these is required: $find_tool_names" + ($find_tool_res --version /dev/null 2>&1 \ + || die "${find_tool_error_prefix}cannot run $find_tool_res --version" + eval "$find_tool_envvar=\$find_tool_res" + eval "export $find_tool_envvar" +} + +## ------ ## +## Main. ## +## ------ ## + +# Requirements: everything required to bootstrap your package, plus +# these. +find_tool CVS cvs +find_tool GIT git +find_tool RSYNC rsync +find_tool XARGS gxargs xargs + +builddir=. +dryrun= +rm_stale='echo' +while test $# != 0 +do + # Handle --option=value by splitting apart and putting back on argv. + case $1 in + --*=*) + opt=$(echo "$1" | sed -e 's/=.*//') + val=$(echo "$1" | sed -e 's/[^=]*=//') + shift + set dummy "$opt" "$val" "$@"; shift + ;; + esac + + case $1 in + --help|--version) ${1#--};; + -C|--builddir) shift; builddir=$1; shift ;; + -n|--dry-run) dryrun=echo; shift;; + -m|--mirror) rm_stale=''; shift;; + --*) die "unrecognized option: $1";; + *) break;; + esac +done + +test $# = 0 \ + || die "too many arguments" + +prev=.prev-version +version=$(cat $prev) || die "no $prev file?" +pkg=$(sed -n 's/^PACKAGE = \(.*\)/\1/p' $builddir/Makefile) \ + || die "no Makefile?" +tmp_branch=web-doc-$version-$$ +current_branch=$($GIT branch | sed -ne '/^\* /{s///;p;q;}') + +cleanup() +{ + __st=$? + $dryrun rm -rf "$tmp" + $GIT checkout "$current_branch" + $GIT submodule update --recursive + $GIT branch -d $tmp_branch + exit $__st +} +trap cleanup 0 +trap 'exit $?' 1 2 13 15 + +# We must build using sources for which --version reports the +# just-released version number, not some string like 7.6.18-20761. +# That version string propagates into all documentation. +set -e +$GIT checkout -b $tmp_branch v$version +$GIT submodule update --recursive +./bootstrap +srcdir=$(pwd) +cd "$builddir" +builddir=$(pwd) + ./config.status --recheck + ./config.status + make + make web-manual +cd "$srcdir" +set +e + +tmp=$(mktemp -d web-doc-update.XXXXXX) || exit 1 +( cd $tmp \ + && $CVS -d $USER@cvs.sv.gnu.org:/webcvs/$pkg co $pkg ) +$RSYNC -avP "$builddir"/doc/manual/ $tmp/$pkg/manual + +( + cd $tmp/$pkg/manual + + # Add all the files. This is simpler than trying to add only the + # new ones because of new directories + # First add non empty dirs individually + find . -name CVS -prune -o -type d \! -empty -print \ + | $XARGS -n1 --no-run-if-empty -- $dryrun $CVS add -ko + # Now add all files + find . -name CVS -prune -o -type f -print \ + | $XARGS --no-run-if-empty -- $dryrun $CVS add -ko + + # Report/Remove stale files + # excluding doc server specific files like CVS/* and .symlinks + if test -n "$rm_stale"; then + echo 'Consider the --mirror option if all of the manual is generated,' >&2 + echo 'which will run `cvs remove` to remove stale files.' >&2 + fi + { find . \( -name CVS -o -type f -name '.*' \) -prune -o -type f -print + (cd "$builddir"/doc/manual/ && find . -type f -print | sed p) + } | sort | uniq -u \ + | $XARGS --no-run-if-empty -- ${rm_stale:-$dryrun} $CVS remove -f + + $dryrun $CVS ci -m $version +) + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "VERSION=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/build-aux/gnupload b/build-aux/gnupload new file mode 100755 index 0000000..2a0bfa3 --- /dev/null +++ b/build-aux/gnupload @@ -0,0 +1,440 @@ +#!/bin/sh +# Sign files and upload them. + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 2004-2018 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Originally written by Alexandre Duret-Lutz . +# The master copy of this file is maintained in the gnulib Git repository. +# Please send bug reports and feature requests to bug-gnulib@gnu.org. + +set -e + +GPG='gpg --batch --no-tty' +conffile=.gnuploadrc +to= +dry_run=false +replace= +symlink_files= +delete_files= +delete_symlinks= +collect_var= +dbg= +nl=' +' + +usage="Usage: $0 [OPTION]... [CMD] FILE... [[CMD] FILE...] + +Sign all FILES, and process them at the destinations specified with --to. +If CMD is not given, it defaults to uploading. See examples below. + +Commands: + --delete delete FILES from destination + --symlink create symbolic links + --rmsymlink remove symbolic links + -- treat the remaining arguments as files to upload + +Options: + --to DEST specify a destination DEST for FILES + (multiple --to options are allowed) + --user NAME sign with key NAME + --replace allow replacements of existing files + --symlink-regex[=EXPR] use sed script EXPR to compute symbolic link names + --dry-run do nothing, show what would have been done + (including the constructed directive file) + --version output version information and exit + --help print this help text and exit + +If --symlink-regex is given without EXPR, then the link target name +is created by replacing the version information with '-latest', e.g.: + foo-1.3.4.tar.gz -> foo-latest.tar.gz + +Recognized destinations are: + alpha.gnu.org:DIRECTORY + savannah.gnu.org:DIRECTORY + savannah.nongnu.org:DIRECTORY + ftp.gnu.org:DIRECTORY + build directive files and upload files by FTP + download.gnu.org.ua:{alpha|ftp}/DIRECTORY + build directive files and upload files by SFTP + [user@]host:DIRECTORY upload files with scp + +Options and commands are applied in order. If the file $conffile exists +in the current working directory, its contents are prepended to the +actual command line options. Use this to keep your defaults. Comments +(#) and empty lines in $conffile are allowed. + + +gives some further background. + +Examples: +1. Upload foobar-1.0.tar.gz to ftp.gnu.org: + gnupload --to ftp.gnu.org:foobar foobar-1.0.tar.gz + +2. Upload foobar-1.0.tar.gz and foobar-1.0.tar.xz to ftp.gnu.org: + gnupload --to ftp.gnu.org:foobar foobar-1.0.tar.gz foobar-1.0.tar.xz + +3. Same as above, and also create symbolic links to foobar-latest.tar.*: + gnupload --to ftp.gnu.org:foobar \\ + --symlink-regex \\ + foobar-1.0.tar.gz foobar-1.0.tar.xz + +4. Upload foobar-0.9.90.tar.gz to two sites: + gnupload --to alpha.gnu.org:foobar \\ + --to sources.redhat.com:~ftp/pub/foobar \\ + foobar-0.9.90.tar.gz + +5. Delete oopsbar-0.9.91.tar.gz and upload foobar-0.9.91.tar.gz + (the -- terminates the list of files to delete): + gnupload --to alpha.gnu.org:foobar \\ + --to sources.redhat.com:~ftp/pub/foobar \\ + --delete oopsbar-0.9.91.tar.gz \\ + -- foobar-0.9.91.tar.gz + +gnupload executes a program ncftpput to do the transfers; if you don't +happen to have an ncftp package installed, the ncftpput-ftp script in +the build-aux/ directory of the gnulib package +(https://savannah.gnu.org/projects/gnulib) may serve as a replacement. + +Send patches and bug reports to ." + +# Read local configuration file +if test -r "$conffile"; then + echo "$0: Reading configuration file $conffile" + conf=`sed 's/#.*$//;/^$/d' "$conffile" | tr "\015$nl" ' '` + eval set x "$conf \"\$@\"" + shift +fi + +while test -n "$1"; do + case $1 in + -*) + collect_var= + case $1 in + --help) + echo "$usage" + exit $? + ;; + --to) + if test -z "$2"; then + echo "$0: Missing argument for --to" 1>&2 + exit 1 + elif echo "$2" | grep 'ftp-upload\.gnu\.org' >/dev/null; then + echo "$0: Use ftp.gnu.org:PKGNAME or alpha.gnu.org:PKGNAME" >&2 + echo "$0: for the destination, not ftp-upload.gnu.org (which" >&2 + echo "$0: is used for direct ftp uploads, not with gnupload)." >&2 + echo "$0: See --help and its examples if need be." >&2 + exit 1 + else + to="$to $2" + shift + fi + ;; + --user) + if test -z "$2"; then + echo "$0: Missing argument for --user" 1>&2 + exit 1 + else + GPG="$GPG --local-user $2" + shift + fi + ;; + --delete) + collect_var=delete_files + ;; + --replace) + replace="replace: true" + ;; + --rmsymlink) + collect_var=delete_symlinks + ;; + --symlink-regex=*) + symlink_expr=`expr "$1" : '[^=]*=\(.*\)'` + ;; + --symlink-regex) + symlink_expr='s|-[0-9][0-9\.]*\(-[0-9][0-9]*\)\{0,1\}\.|-latest.|' + ;; + --symlink) + collect_var=symlink_files + ;; + --dry-run|-n) + dry_run=: + ;; + --version) + echo "gnupload $scriptversion" + exit $? + ;; + --) + shift + break + ;; + -*) + echo "$0: Unknown option '$1', try '$0 --help'" 1>&2 + exit 1 + ;; + esac + ;; + *) + if test -z "$collect_var"; then + break + else + eval "$collect_var=\"\$$collect_var $1\"" + fi + ;; + esac + shift +done + +dprint() +{ + echo "Running $* ..." +} + +if $dry_run; then + dbg=dprint +fi + +if test -z "$to"; then + echo "$0: Missing destination sites" >&2 + exit 1 +fi + +if test -n "$symlink_files"; then + x=`echo "$symlink_files" | sed 's/[^ ]//g;s/ //g'` + if test -n "$x"; then + echo "$0: Odd number of symlink arguments" >&2 + exit 1 + fi +fi + +if test $# = 0; then + if test -z "${symlink_files}${delete_files}${delete_symlinks}"; then + echo "$0: No file to upload" 1>&2 + exit 1 + fi +else + # Make sure all files exist. We don't want to ask + # for the passphrase if the script will fail. + for file + do + if test ! -f $file; then + echo "$0: Cannot find '$file'" 1>&2 + exit 1 + elif test -n "$symlink_expr"; then + linkname=`echo $file | sed "$symlink_expr"` + if test -z "$linkname"; then + echo "$0: symlink expression produces empty results" >&2 + exit 1 + elif test "$linkname" = $file; then + echo "$0: symlink expression does not alter file name" >&2 + exit 1 + fi + fi + done +fi + +# Make sure passphrase is not exported in the environment. +unset passphrase +unset passphrase_fd_0 +GNUPGHOME=${GNUPGHOME:-$HOME/.gnupg} + +# Reset PATH to be sure that echo is a built-in. We will later use +# 'echo $passphrase' to output the passphrase, so it is important that +# it is a built-in (third-party programs tend to appear in 'ps' +# listings with their arguments...). +# Remember this script runs with 'set -e', so if echo is not built-in +# it will exit now. +if $dry_run || grep -q "^use-agent" $GNUPGHOME/gpg.conf; then :; else + PATH=/empty echo -n "Enter GPG passphrase: " + stty -echo + read -r passphrase + stty echo + echo + passphrase_fd_0="--passphrase-fd 0" +fi + +if test $# -ne 0; then + for file + do + echo "Signing $file ..." + rm -f $file.sig + echo "$passphrase" | $dbg $GPG $passphrase_fd_0 -ba -o $file.sig $file + done +fi + + +# mkdirective DESTDIR BASE FILE STMT +# Arguments: See upload, below +mkdirective () +{ + stmt="$4" + if test -n "$3"; then + stmt=" +filename: $3$stmt" + fi + + cat >${2}.directive<&2 + fi + $dbg ncftpput savannah.gnu.org /incoming/savannah/$destdir $files + ;; + savannah.nongnu.org:*) + if test -z "$files"; then + echo "$0: warning: standalone directives not applicable for $dest" >&2 + fi + $dbg ncftpput savannah.nongnu.org /incoming/savannah/$destdir $files + ;; + download.gnu.org.ua:alpha/*|download.gnu.org.ua:ftp/*) + destdir_p1=`echo "$destdir" | sed 's,^[^/]*/,,'` + destdir_topdir=`echo "$destdir" | sed 's,/.*,,'` + mkdirective "$destdir_p1" "$base" "$file" "$stmt" + echo "$passphrase" | $dbg $GPG $passphrase_fd_0 --clearsign $base.directive + for f in $files $base.directive.asc + do + echo put $f + done | $dbg sftp -b - puszcza.gnu.org.ua:/incoming/$destdir_topdir + ;; + /*) + dest_host=`echo "$dest" | sed 's,:.*,,'` + mkdirective "$destdir" "$base" "$file" "$stmt" + echo "$passphrase" | $dbg $GPG $passphrase_fd_0 --clearsign $base.directive + $dbg cp $files $base.directive.asc $dest_host + ;; + *) + if test -z "$files"; then + echo "$0: warning: standalone directives not applicable for $dest" >&2 + fi + $dbg scp $files $dest + ;; + esac + rm -f $base.directive $base.directive.asc +} + +##### +# Process any standalone directives +stmt= +if test -n "$symlink_files"; then + stmt="$stmt +`mksymlink $symlink_files`" +fi + +for file in $delete_files +do + stmt="$stmt +archive: $file" +done + +for file in $delete_symlinks +do + stmt="$stmt +rmsymlink: $file" +done + +if test -n "$stmt"; then + for dest in $to + do + destdir=`echo $dest | sed 's/[^:]*://'` + upload "$dest" "$destdir" "`hostname`-$$" "" "$stmt" + done +fi + +# Process actual uploads +for dest in $to +do + for file + do + echo "Uploading $file to $dest ..." + stmt= + # + # allowing file replacement is all or nothing. + if test -n "$replace"; then stmt="$stmt +$replace" + fi + # + files="$file $file.sig" + destdir=`echo $dest | sed 's/[^:]*://'` + if test -n "$symlink_expr"; then + linkname=`echo $file | sed "$symlink_expr"` + stmt="$stmt +symlink: $file $linkname +symlink: $file.sig $linkname.sig" + fi + upload "$dest" "$destdir" "$file" "$file" "$stmt" "$files" + done +done + +exit 0 + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: From 28624af154f5456007e9c8d6e2624ef0efac1186 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 18 Mar 2018 22:05:15 +0100 Subject: [PATCH 152/239] maint: Add ".prev-version" This file is used by the "build-aux/do-release-commit-and-tag" script. * .prev-version: New file --- .prev-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .prev-version diff --git a/.prev-version b/.prev-version new file mode 100644 index 0000000..b0f3d96 --- /dev/null +++ b/.prev-version @@ -0,0 +1 @@ +1.0.8 From 2961ae8033a7a20d6bd6c665a7266728ad2e6edd Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 19 Mar 2018 00:19:13 +0100 Subject: [PATCH 153/239] version 1.1 * NEWS: Record release date. --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 3b832d3..0729c5a 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ GNU Mcron NEWS -*- outline -*- -* Noteworthy changes in release ?.? (????-??-??) [?] +* Noteworthy changes in release 1.1 (2018-03-19) [stable] ** New features From bb8414e00d86e5c127b88f732b6fa119cb47fb32 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 19 Mar 2018 00:37:25 +0100 Subject: [PATCH 154/239] maint: Post-release administrivia * NEWS: Add header line for next release. * .prev-version: Record previous version. --- .prev-version | 2 +- NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.prev-version b/.prev-version index b0f3d96..9459d4b 100644 --- a/.prev-version +++ b/.prev-version @@ -1 +1 @@ -1.0.8 +1.1 diff --git a/NEWS b/NEWS index 0729c5a..524008c 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,8 @@ GNU Mcron NEWS -*- outline -*- +* Noteworthy changes in release ?.? (????-??-??) [?] + + * Noteworthy changes in release 1.1 (2018-03-19) [stable] ** New features From 98eaa3fb9c5b57d37c08725e306118e58036374f Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 19 Mar 2018 22:37:54 +0100 Subject: [PATCH 155/239] maint: Remove obsolete configure checks * configure.ac: Don't check for 'sed' and 'cp' programs which are considered portable. Don't check for 'head' and 'which' programs which are not required. --- configure.ac | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/configure.ac b/configure.ac index 0ce6475..f741d1a 100644 --- a/configure.ac +++ b/configure.ac @@ -49,24 +49,6 @@ GUILE_PROGS AM_MISSING_PROG(HELP2MAN, help2man, $missing_dir) -AC_CHECK_PROGS(SED, sed) -if test "x$ac_cv_prog_SED" = "x"; then - AC_MSG_ERROR(sed not found) -fi -AC_CHECK_PROGS(HEAD, head) -if test "x$ac_cv_prog_HEAD" = "x"; then - AC_MSG_ERROR(head not found) -fi -AC_CHECK_PROGS(WHICH, which) -if test "x$ac_cv_prog_WHICH" = "x"; then - AC_MSG_ERROR(which not found) -fi -AC_CHECK_PROGS(CP, cp) -if test "x$ac_cv_prog_CP" = "x"; then - AC_MSG_ERROR(cp not found) -fi - - # Now find a sendmail or equivalent. AC_CHECK_PROGS(SENDMAIL, sendmail) From 22ba12d1aa0f6380146f6e66382dbc1058c30625 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 19 Mar 2018 23:01:09 +0100 Subject: [PATCH 156/239] build: Reverse '--disable-multi-user' effect This fixes a bug where the '--disable-multi-user' was actually having the reverse effect of installing 'cron' and 'crontab'. * configure.ac: Reverse equality test when setting 'MULTI_USER' Automake conditional. --- NEWS | 4 ++++ configure.ac | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 524008c..7cbf969 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ GNU Mcron NEWS -*- outline -*- * Noteworthy changes in release ?.? (????-??-??) [?] +** Bug fixes + + The "--disable-multi-user" configure variable is not reversed anymore. + 'cron' and 'crontab' are now installed unless this option is used. * Noteworthy changes in release 1.1 (2018-03-19) [stable] diff --git a/configure.ac b/configure.ac index f741d1a..0a61bb4 100644 --- a/configure.ac +++ b/configure.ac @@ -75,7 +75,7 @@ AC_ARG_ENABLE([multi-user], [Don't Install legacy cron and crontab programs])], [enable_multi_user="$enableval"], [enable_multi_user="yes"]) -AM_CONDITIONAL([MULTI_USER], [test "x$enable_multi_user" != xyes]) +AM_CONDITIONAL([MULTI_USER], [test "x$enable_multi_user" = xyes]) # Configure the various files that mcron uses at runtime. From dd9d6a6b06f3ec249757c728dc1568b2e4efbd3f Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 19 Mar 2018 23:31:30 +0100 Subject: [PATCH 157/239] build: Handle all programs names transformations Previously only prepending a prefix was handled when installing 'crontab'. Using the 'transform' Make macro allows the installation process to support generic transformations as defined by the '--program-suffix' and '--program-transform-name' configure options. * configure.ac: Don't substitue '@real_program_prefix@'. * Makefile.am (fpp): Remove. (transform_exe): New macro. [MULTI_USER] (install-exec-hook): Use it when installing 'crontab'. --- Makefile.am | 7 ++++--- configure.ac | 8 -------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/Makefile.am b/Makefile.am index 1e953c6..96b67c1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -172,12 +172,13 @@ EXTRA_DIST = \ ## Installation. ## ## -------------- ## -#full program prefix -fpp = $(DESTDIR)$(bindir)/@real_program_prefix@ +# Sed command for Transforming program names. +transform_exe = s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/ if MULTI_USER install-exec-hook: - chmod u+s $(fpp)crontab$(EXEEXT) + tcrontab=`echo crontab$(EXEEXT) | sed '$(transform_exe)'`; \ + chmod u+s $(DESTDIR)$(bindir)/$${tcrontab} endif ## --------------- ## diff --git a/configure.ac b/configure.ac index 0a61bb4..d0d421c 100644 --- a/configure.ac +++ b/configure.ac @@ -133,14 +133,6 @@ AC_ARG_WITH(tmp-dir, AC_MSG_RESULT($CONFIG_TMP_DIR) AC_SUBST(CONFIG_TMP_DIR) - - - -# This is to support `make DESTDIR=...' - -real_program_prefix=`echo $program_prefix | sed s/NONE//` -AC_SUBST(real_program_prefix) - AC_CONFIG_FILES([pre-inst-env:build-aux/pre-inst-env.in], [chmod +x pre-inst-env]) AC_CONFIG_FILES([doc/config.texi From 624ceb44809f2be891f0af82df1d917d4a5aa9c1 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 20 Mar 2018 00:57:02 +0100 Subject: [PATCH 158/239] build: Properly set Guile load paths in programs This fixes an issue where the installed Guile load paths were set by the undefined 'moduledir' Make macro. * Makefile.am (AM_CPPFLAGS): Define PACKAGE_LOAD_PATH with 'guilesitedir' macro and PACKAGE_LOAD_COMPILED_PATH with 'guilesitegodir'. * NEWS: Update. --- Makefile.am | 4 ++-- NEWS | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 96b67c1..6a01ec9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,8 +31,8 @@ noinst_PROGRAMS = bin/cron bin/crontab endif AM_CPPFLAGS = \ - -DPACKAGE_LOAD_PATH=\"$(moduledir)\" \ - -DPACKAGE_LOAD_COMPILED_PATH=\"$(moduledir)\" \ + -DPACKAGE_LOAD_PATH=\"$(guilesitedir)\" \ + -DPACKAGE_LOAD_COMPILED_PATH=\"$(guilesitegodir)\" \ -D_GNU_SOURCE AM_CFLAGS = @GUILE_CFLAGS@ diff --git a/NEWS b/NEWS index 7cbf969..a5f2c80 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,9 @@ GNU Mcron NEWS -*- outline -*- The "--disable-multi-user" configure variable is not reversed anymore. 'cron' and 'crontab' are now installed unless this option is used. + The programs now sets the GUILE_LOAD_PATH and GUILE_LOAD_COMPILED_PATH + environment variables with the location of the installed Guile modules. + * Noteworthy changes in release 1.1 (2018-03-19) [stable] ** New features From 64ff2b1ddfff20df87ce4e7c13bd4f996d8948cb Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 20 Mar 2018 01:16:35 +0100 Subject: [PATCH 159/239] build: Support 'make installcheck' * configure.ac: Pass 'std-options' to AM_INIT_AUTOMAKE to check that the "--help" and "--version" options can be passed to installed programs. * Makefile.am (installcheck-local): New rule which checks the programs presence and configuration. --- Makefile.am | 16 ++++++++++++++++ configure.ac | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 6a01ec9..2b2f92e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -181,6 +181,22 @@ install-exec-hook: chmod u+s $(DESTDIR)$(bindir)/$${tcrontab} endif +installcheck-local: +## Check that only expected programs are installed and configured + tmcron=`echo mcron$(EXEEXT) | sed '$(transform_exe)'`; \ + test -e $(DESTDIR)$(bindir)/$${tmcron} +if MULTI_USER + tcrontab=`echo crontab$(EXEEXT) | sed '$(transform_exe)'`; \ + test -u $(DESTDIR)$(bindir)/$${tcrontab} + tcron=`echo cron$(EXEEXT) | sed '$(transform_exe)'`; \ + test -e $(DESTDIR)$(sbindir)/$${tcron} +else !MULTI_USER + tcrontab=`echo crontab$(EXEEXT) | sed '$(transform_exe)'`; \ + test ! -u $(DESTDIR)$(bindir)/$${tcrontab} + tcron=`echo cron$(EXEEXT) | sed '$(transform_exe)'`; \ + test ! -f $(DESTDIR)$(sbindir)/$${tcron} +endif !MULTI_USER + ## --------------- ## ## Documentation. ## ## --------------- ## diff --git a/configure.ac b/configure.ac index d0d421c..29f9f60 100644 --- a/configure.ac +++ b/configure.ac @@ -26,7 +26,7 @@ AC_CONFIG_SRCDIR([src/mcron.c]) AC_CONFIG_AUX_DIR([build-aux]) AC_REQUIRE_AUX_FILE([test-driver.scm]) AC_REQUIRE_AUX_FILE([git-version-gen]) -AM_INIT_AUTOMAKE([subdir-objects -Wall -Wno-override]) +AM_INIT_AUTOMAKE([subdir-objects -Wall -Wno-override std-options]) AM_SILENT_RULES([yes]) # enables silent rules by default AC_CANONICAL_HOST From 44f4fab6414e15b49a6f7dc5bba0e3ab8e9e0a87 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 20 Mar 2018 02:28:10 +0100 Subject: [PATCH 160/239] maint: Update NEWS * NEWS: Announce the availability of 'make installcheck'. --- NEWS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/NEWS b/NEWS index a5f2c80..528b4d3 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,11 @@ GNU Mcron NEWS -*- outline -*- The programs now sets the GUILE_LOAD_PATH and GUILE_LOAD_COMPILED_PATH environment variables with the location of the installed Guile modules. +** Improvements + + Some basic tests for the installed programs can be run after 'make install' + with 'make installcheck'. + * Noteworthy changes in release 1.1 (2018-03-19) [stable] ** New features From 09e452b62a82845736e638eecd762a911d95a349 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 20 Mar 2018 14:33:56 +0100 Subject: [PATCH 161/239] tests: Set timezone in "schedule.sh" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the test environment was implicitly expecting the current timezone to be UTC+1. * tests/schedule.sh: Set TZ environment variable to 'UTC0'. Update expected result. Reported-by: Ludovic Courtès --- tests/schedule.sh | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/tests/schedule.sh b/tests/schedule.sh index ad267c4..5ea79e5 100644 --- a/tests/schedule.sh +++ b/tests/schedule.sh @@ -1,5 +1,5 @@ # schedule.sh -- Check mcron schedule output -# Copyright © 2017 Mathieu Lirzin +# Copyright © 2017, 2018 Mathieu Lirzin # # This file is part of GNU Mcron. # @@ -18,9 +18,14 @@ source "${srcdir}/tests/init.sh" +# Use UTC and SOURCE_DATE_EPOCH to get reproducible result. + SOURCE_DATE_EPOCH=1 export SOURCE_DATE_EPOCH +TZ=UTC0 +export TZ + # Use current working directory to store mcron files XDG_CONFIG_HOME=`pwd` export XDG_CONFIG_HOME @@ -35,83 +40,83 @@ cat > cron/bar.guile < expected < Date: Tue, 20 Mar 2018 14:44:54 +0100 Subject: [PATCH 162/239] utils: Use 'scandir' instead of custom 'for-each-file' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * src/mcron/utils.scm (for-each-file): Delete. * src/mcron/scripts/cron.scm (process-files-in-system-directory): Use 'scandir' which has the benefit of being deterministic. * src/mcron/scripts/mcron.scm (process-files-in-user-directory): Likewise. * tests/schedule.sh: Update expected output which is now more reliable. * NEWS: Update. Suggested-by: Ludovic Courtès --- NEWS | 2 ++ src/mcron/scripts/cron.scm | 7 ++++--- src/mcron/scripts/mcron.scm | 12 ++++++------ src/mcron/utils.scm | 15 +-------------- tests/schedule.sh | 26 +++++++++++++------------- 5 files changed, 26 insertions(+), 36 deletions(-) diff --git a/NEWS b/NEWS index 528b4d3..cf51e2c 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,8 @@ GNU Mcron NEWS -*- outline -*- Some basic tests for the installed programs can be run after 'make install' with 'make installcheck'. + The configuration files are now processed using a deterministic order. + * Noteworthy changes in release 1.1 (2018-03-19) [stable] ** New features diff --git a/src/mcron/scripts/cron.scm b/src/mcron/scripts/cron.scm index 5052c32..323499e 100644 --- a/src/mcron/scripts/cron.scm +++ b/src/mcron/scripts/cron.scm @@ -1,6 +1,6 @@ ;;;; cron -- daemon for running jobs at scheduled times ;;; Copyright © 2003, 2012 Dale Mellor -;;; Copyright © 2015, 2016 Mathieu Lirzin +;;; Copyright © 2015, 2016, 2018 Mathieu Lirzin ;;; ;;; This file is part of GNU Mcron. ;;; @@ -18,6 +18,7 @@ ;;; along with GNU Mcron. If not, see . (define-module (mcron scripts cron) + #:use-module (ice-9 ftw) #:use-module (mcron base) #:use-module (mcron config) #:use-module (mcron job-specifier) @@ -84,13 +85,13 @@ operation. The permissions on the /var/cron/tabs directory enforce this." (catch #t (λ () - (for-each-file + (for-each (λ (user) (and-let* ((entry (user-entry user))) ;crontab without user? (set-configuration-user entry) (catch-mcron-error (read-vixie-file (string-append config-spool-dir "/" user))))) - config-spool-dir)) + (scandir config-spool-dir))) (λ (key . args) (mcron-error 4 "You do not have permission to access the system crontabs.")))) diff --git a/src/mcron/scripts/mcron.scm b/src/mcron/scripts/mcron.scm index afb380f..6545ada 100644 --- a/src/mcron/scripts/mcron.scm +++ b/src/mcron/scripts/mcron.scm @@ -1,6 +1,6 @@ ;;;; mcron -- run jobs at scheduled times ;;; Copyright © 2003, 2012 Dale Mellor -;;; Copyright © 2015, 2016 Mathieu Lirzin +;;; Copyright © 2015, 2016, 2018 Mathieu Lirzin ;;; ;;; This file is part of GNU Mcron. ;;; @@ -18,6 +18,7 @@ ;;; along with GNU Mcron. If not, see . (define-module (mcron scripts mcron) + #:use-module (ice-9 ftw) #:use-module (mcron base) #:use-module (mcron config) #:use-module (mcron job-specifier) ;for user/system files @@ -49,11 +50,10 @@ $XDG_CONFIG_HOME is not defined uses ~/.config/cron instead)." (map (λ (dir) (catch #t (λ () - (for-each-file - (λ (file) - (process-user-file (string-append dir "/" file) - #:input input-type)) - dir)) + (for-each (λ (file) + (process-user-file (string-append dir "/" file) + #:input input-type)) + (scandir dir))) (λ (key . args) (set! errors (1+ errors))))) (list (string-append home-directory "/.cron") diff --git a/src/mcron/utils.scm b/src/mcron/utils.scm index 062e756..bb23f4a 100644 --- a/src/mcron/utils.scm +++ b/src/mcron/utils.scm @@ -1,6 +1,6 @@ ;;;; utils.scm -- helper procedures ;;; Copyright © 2003, 2012 Dale Mellor -;;; Copyright © 2015, 2016 Mathieu Lirzin +;;; Copyright © 2015, 2016, 2018 Mathieu Lirzin ;;; ;;; This file is part of GNU Mcron. ;;; @@ -29,7 +29,6 @@ parse-args show-version show-package-information - for-each-file process-update-request) #:re-export (option-ref read-string)) @@ -81,18 +80,6 @@ General help using GNU software: \n" config-package-name config-package-url)) -(define (for-each-file proc directory) - "Apply PROC to each file in DIRECTORY. DIRECTORY must be a valid directory name. -PROC must be a procedure that take one file name argument. The return value -is not specified" - (let ((dir (opendir directory))) - (let loop ((file-name (readdir dir))) - (if (eof-object? file-name) - (closedir dir) - (begin - (proc file-name) - (loop (readdir dir))))))) - (define (process-update-request fdes-list) "Read a user name from the socket, dealing with the /etc/crontab special case, remove all the user's jobs from the job list, and then re-read the diff --git a/tests/schedule.sh b/tests/schedule.sh index 5ea79e5..d403f1d 100644 --- a/tests/schedule.sh +++ b/tests/schedule.sh @@ -41,14 +41,10 @@ EOF cat > expected < output From fe9592fd28f3ea180858fd1526ab8f67c54f1d09 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 20 Mar 2018 18:31:37 +0100 Subject: [PATCH 163/239] maint: Update copyright years --- Makefile.am | 2 +- NEWS | 2 +- configure.ac | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 2b2f92e..e37b0f4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. # Copyright © 2003 Dale Mellor -# Copyright © 2015, 2016, 2017 Mathieu Lirzin +# Copyright © 2015, 2016, 2017, 2018 Mathieu Lirzin # # This file is part of GNU Mcron. # diff --git a/NEWS b/NEWS index cf51e2c..f27a92c 100644 --- a/NEWS +++ b/NEWS @@ -144,7 +144,7 @@ GNU Mcron NEWS -*- outline -*- ======================================================================== Copyright © 2003, 2005, 2006 Dale Mellor -Copyright © 2017 Mathieu Lirzin +Copyright © 2017, 2018 Mathieu Lirzin Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright diff --git a/configure.ac b/configure.ac index 29f9f60..dfb756a 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ ## Process this file with autoconf to produce a configure script. # Copyright © 2003, 2005, 2012, 2014 Dale Mellor # -# Copyright © 2015, 2016, 2017 Mathieu Lirzin +# Copyright © 2015, 2016, 2017, 2018 Mathieu Lirzin # # This file is part of GNU Mcron. # From 426f5d7b382b904313227f9bec631b8130573313 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Wed, 21 Mar 2018 01:26:19 +0100 Subject: [PATCH 164/239] job-specifier: Use 'simple-format' * src/mcron/job-specifier.scm (job): Use 'simple-format' instead of 'with-output-to-string'. --- src/mcron/job-specifier.scm | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/mcron/job-specifier.scm b/src/mcron/job-specifier.scm index 401e4d0..d5bf590 100644 --- a/src/mcron/job-specifier.scm +++ b/src/mcron/job-specifier.scm @@ -237,11 +237,10 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." "job: invalid first argument (next-time-function; " "should be function, string or list)")))) (displayable - (cond (displayable displayable) + (cond (displayable displayable) ((procedure? action) "Lambda function") - ((string? action) action) - ((list? action) (with-output-to-string - (lambda () (display action)))))) + ((string? action) action) + ((list? action) (simple-format #f "~A" action)))) (user* (if (or (string? user) (integer? user)) (getpw user) user))) From cae2270fd72961adeae77d21d065bfcb64ca7d77 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Fri, 23 Mar 2018 20:24:17 +0100 Subject: [PATCH 165/239] build: Check non-standard C functions at configure time * configure.ac: Check 'argp_parse' and 'asprintf' presence. --- configure.ac | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/configure.ac b/configure.ac index dfb756a..fbda198 100644 --- a/configure.ac +++ b/configure.ac @@ -43,6 +43,12 @@ GUILE_PKG([2.2 2.0]) # 'config.rpath' script. PKG_CHECK_MODULES(GUILE, [guile-$GUILE_EFFECTIVE_VERSION]) +# Check for 'argp' program arguments parser. +AC_CHECK_FUNC(argp_parse, [], AC_MSG_ERROR([argp not found])) + +# Check for non-POSIX string formatting function. +AC_CHECK_FUNC(asprintf, [], AC_MSG_ERROR([asprintf not found])) + # Checks for programs. GUILE_PROGS From ac39c00859f763933fa86d761812f37862e91b78 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Fri, 23 Mar 2018 21:50:03 +0100 Subject: [PATCH 166/239] base: Add '' record data type Reifying the notion of a schedule helps reasoning about the code. Passing a schedule as an argument to related procedures allows writing simpler unit tests. * src/mcron/base.scm(): New record data type. (make-schedule, schedule-user, set-schedule-user!) (schedule-system, set-schedule-system!) (schedule-current, set-schedule-current!): New procedures. (system-job-list, user-job-list, configuration-source): Replace those global variables with ... (%global-schedule): ... this global instance. * src/mcron/base.scm (use-system-job-list, use-user-job-list) (remove-user-jobs, clear-system-jobs, add-job, find-next-jobs) (display-schedule, run-job-loop): Add '#:SCHEDULE' keyword argument. * doc/mcron.texi (The base module): Update documentation. --- doc/mcron.texi | 15 ++++-- src/mcron/base.scm | 129 ++++++++++++++++++++++++--------------------- 2 files changed, 80 insertions(+), 64 deletions(-) diff --git a/doc/mcron.texi b/doc/mcron.texi index 04f92bd..f408e11 100644 --- a/doc/mcron.texi +++ b/doc/mcron.texi @@ -12,6 +12,7 @@ program for running jobs at scheduled times. Copyright @copyright{} 2003, 2005, 2006, 2012, 2014 Dale Mellor +Copyright @copyright{} 2018 Mathieu Lirzin @quotation Permission is granted to copy, distribute and/or modify this @@ -1196,7 +1197,9 @@ This procedure causes all the environment modifiers that have been specified so far to be forgotten. @end deffn -@deffn{Scheme procedure} add-job time-proc action displayable configuration-time configuration-user +@deffn{Scheme procedure} add-job time-proc action displayable @ + configuration-time configuration-user @ + [#:schedule @var{%global-schedule}] This procedure adds a job specification to the list of all jobs to run. @var{time-proc} should be a procedure taking exactly one argument which will be a UNIX time. This procedure must compute the next time @@ -1211,7 +1214,8 @@ computed. Finally, @var{configuration-user} should be the passwd entry for the user under whose personality the job is to run. @end deffn -@deffn{Scheme procedure} run-job-loop . fd-list +@deffn{Scheme procedure} run-job-loop @var{fd-list} @ + [#:schedule @var{%global-schedule}] @cindex file descriptors @cindex interrupting the mcron loop This procedure returns only under exceptional circumstances, but @@ -1225,15 +1229,16 @@ before calling the @code{run-job-loop} procedure again to resume execution of the mcron base. @end deffn -@deffn{Scheme procedure} remove-user-jobs user - +@deffn{Scheme procedure} remove-user-jobs user @ + [#:schedule @var{%global-schedule}] The argument @var{user} should be a string naming a user (his login name), or an integer UID, or an object representing the user's passwd entry. All jobs on the current job list that are scheduled to be run under this personality are removed from the job list. @end deffn -@deffn{Scheme procedure} display-schedule @var{count} [@var{port}] +@deffn{Scheme procedure} display-schedule @var{count} [@var{port}] @ + [#:schedule @var{%global-schedule}] @cindex schedule of jobs This procedure is used to display a textual list of the next COUNT jobs to run. diff --git a/src/mcron/base.scm b/src/mcron/base.scm index 3528236..5cfc92c 100644 --- a/src/mcron/base.scm +++ b/src/mcron/base.scm @@ -1,6 +1,6 @@ ;;;; base.scm -- core procedures ;;; Copyright © 2003 Dale Mellor -;;; Copyright © 2015, 2016 Mathieu Lirzin +;;; Copyright © 2015, 2016, 2018 Mathieu Lirzin ;;; Copyright © 2016 Ludovic Courtès ;;; ;;; This file is part of GNU Mcron. @@ -18,6 +18,13 @@ ;;; You should have received a copy of the GNU General Public License ;;; along with GNU Mcron. If not, see . +;;;; Commentary: +;;; +;;; This module provides the core data structures for scheduling jobs and the +;;; procedures for running those jobs. +;;; +;;;; Code: + (define-module (mcron base) #:use-module (ice-9 match) #:use-module (mcron environment) @@ -35,30 +42,6 @@ #:re-export (clear-environment-mods append-environment-mods)) -;; The list of all jobs known to the system. Each element of the list is -;; -;; (make-job user next-time-function action environment displayable next-time) -;; -;; where action must be a procedure, and the environment is an alist of -;; modifications that need making to the UNIX environment before the action is -;; run. The next-time element is the only one that is modified during the -;; running of a cron process (i.e. all the others are set once and for all at -;; configuration time). -;; -;; The reason we maintain two lists is that jobs in /etc/crontab may be placed -;; in one, and all other jobs go in the other. This makes it possible to remove -;; all the jobs in the first list in one go, and separately we can remove all -;; jobs from the second list which belong to a particular user. This behaviour -;; is required for full vixie compatibility. - -(define system-job-list '()) -(define user-job-list '()) - -(define configuration-source 'user) - -(define (use-system-job-list) (set! configuration-source 'system)) -(define (use-user-job-list) (set! configuration-source 'user)) - ;; A cron job. (define-record-type (make-job user time-proc action environment displayable next-time) @@ -66,52 +49,78 @@ (user job:user) ;object : passwd entry (time-proc job:next-time-function) ;proc : with one 'time' parameter (action job:action) ;thunk : user's code + ;; Environment variables that need to be set before the ACTION is run. (environment job:environment) ;alist : environment variables (displayable job:displayable) ;string : visible in schedule (next-time job:next-time ;number : time in UNIX format job:next-time-set!)) -;; Remove jobs from the user-job-list belonging to this user. +;; A schedule of cron jobs. +(define-record-type + ;; The schedule is composed of a 'user' and 'system' schedule. This makes + ;; removing all the jobs belonging to one group easy, which is required for + ;; full vixie compatibility. + (make-schedule user system current) + schedule? + ;; list for jobs that may be placed in '/etc/crontab'. + (system schedule-system set-schedule-system!) ;list of + ;; list for all other jobs. + (user schedule-user set-schedule-user!) ;list of + (current schedule-current set-schedule-current!)) ;symbol 'user or 'system -(define (remove-user-jobs user) - (if (or (string? user) - (integer? user)) - (set! user (getpw user))) - (set! user-job-list - (remove (lambda (job) (eqv? (passwd:uid user) - (passwd:uid (job:user job)))) - user-job-list))) +(define %global-schedule + ;; Global schedule used by 'mcron' and 'cron'. + (make-schedule '() '() 'user)) +(define* (use-system-job-list #:key (schedule %global-schedule)) + "Mutate '%global-schedule' to use system jobs. +This procedure is deprecated." + (set-schedule-current! schedule 'system)) +(define* (use-user-job-list #:key (schedule %global-schedule)) + "Mutate '%global-schedule' to use user jobs. +This procedure is deprecated." + (set-schedule-current! schedule 'user)) -;; Remove all the jobs on the system job list. +(define* (remove-user-jobs user #:key (schedule %global-schedule)) + "Remove user jobs from SCHEDULE belonging to USER. USER must be either a +username, a UID, or a passwd entry." + (let ((user* (if (or (string? user) (integer? user)) + (getpw user) + user))) + (set-schedule-user! schedule + (filter (lambda (job) + (not (eqv? (passwd:uid user*) + (passwd:uid (job:user job))))) + (schedule-user schedule))))) -(define (clear-system-jobs) (set! system-job-list '())) +(define* (clear-system-jobs #:key (schedule %global-schedule)) + "Remove all the system jobs from SCHEDULE." + (set-schedule-system! schedule '())) - - -;; Add a new job with the given specifications to the head of the appropriate -;; jobs list. - -(define (add-job time-proc action displayable configuration-time - configuration-user) +(define* (add-job time-proc action displayable configuration-time + configuration-user + #:key (schedule %global-schedule)) + "Add a new job with the given specifications to the current job set in +SCHEDULE." (let ((entry (make-job configuration-user time-proc action (get-current-environment-mods-copy) displayable (time-proc configuration-time)))) - (if (eq? configuration-source 'user) - (set! user-job-list (cons entry user-job-list)) - (set! system-job-list (cons entry system-job-list))))) + (if (eq? (schedule-current schedule) 'user) + (set-schedule-user! schedule (cons entry (schedule-user schedule))) + (set-schedule-system! schedule + (cons entry (schedule-system schedule)))))) -(define (find-next-jobs) - "Procedure to locate the jobs in the global job-list with the -lowest (soonest) next-times. These are the jobs for which we must schedule -the mcron program (under any personality) to next wake up. The return value -is a cons cell consisting of the next time (maintained in the next-time -variable) and a list of the job entries that are to run at this -time (maintained in the next-jobs-list variable). +(define* (find-next-jobs #:key (schedule %global-schedule)) + "Procedure to locate the jobs in SCHEDULE with the lowest (soonest) +next-times. These are the jobs for which we must schedule the mcron +program (under any personality) to next wake up. The return value is a cons +cell consisting of the next time (maintained in the next-time variable) and a +list of the job entries that are to run at this time (maintained in the +next-jobs-list variable). The procedure works by first obtaining the time of the first job on the list, and setting this job in the next-jobs-list. Then for each other entry on the @@ -121,7 +130,8 @@ accomodate, or the job runs at the same time as the next job, in which case the next-jobs-list is simply augmented with the new job, or else the job runs later than others noted in which case we ignore it for now and continue to recurse the list." - (let loop ((jobs (append system-job-list user-job-list)) + (let loop ((jobs + (append (schedule-system schedule) (schedule-user schedule))) (next-time (inf)) (next-jobs '())) (match jobs @@ -136,14 +146,15 @@ recurse the list." (else (loop rest next-time next-jobs)))))))) -(define* (display-schedule count #:optional (port (current-output-port))) +(define* (display-schedule count #:optional (port (current-output-port)) + #:key (schedule %global-schedule)) "Display on PORT a textual list of the next COUNT jobs to run. This simulates the run of the job loop to display the resquested information. Since calling this procedure has the effect of mutating the job timings, the program must exit after. Otherwise the internal data state will be left unusable." (unless (<= count 0) - (match (find-next-jobs) + (match (find-next-jobs #:schedule schedule) ((#f . jobs) #f) ((time . jobs) @@ -156,7 +167,7 @@ unusable." (job:next-time-set! job ((job:next-time-function job) (job:next-time job)))) jobs)))) - (display-schedule (- count 1) port))) + (display-schedule (- count 1) port #:schedule schedule))) ;; For proper housekeeping, it is necessary to keep a record of the number of ;; child processes we fork off to run the jobs. @@ -191,7 +202,7 @@ next value." (eqv? (car (waitpid WAIT_ANY WNOHANG)) 0))) (set! number-children (- number-children 1)))) -(define* (run-job-loop #:optional fd-list) +(define* (run-job-loop #:optional fd-list #:key (schedule %global-schedule)) ;; 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 and reap any children (old jobs) that have completed. Repeat ad @@ -205,7 +216,7 @@ next value." (call-with-current-continuation (lambda (break) (let loop () - (match (find-next-jobs) + (match (find-next-jobs #:schedule schedule) ((next-time . next-jobs-lst) (let ((sleep-time (if next-time (- next-time (current-time)) From 6583e83d16288d78645d806af3e4f69f4f1a655a Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 24 Mar 2018 00:40:04 +0100 Subject: [PATCH 167/239] tests: Add "tests/base.scm" * tests/base.scm: New test. * Makefile.am (TESTS): Add it. --- Makefile.am | 1 + tests/base.scm | 151 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 tests/base.scm diff --git a/Makefile.am b/Makefile.am index e37b0f4..07a492f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -136,6 +136,7 @@ SCM_LOG_DRIVER = \ TESTS = \ tests/basic.sh \ tests/schedule.sh \ + tests/base.scm \ tests/environment.scm \ tests/job-specifier.scm diff --git a/tests/base.scm b/tests/base.scm new file mode 100644 index 0000000..89b7349 --- /dev/null +++ b/tests/base.scm @@ -0,0 +1,151 @@ +;;;; base.scm -- tests for (mcron base) module +;;; Copyright © 2018 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . + +(use-modules (srfi srfi-64) + (mcron base)) + +(test-begin "base") + +(setlocale LC_ALL "C") +(setenv "TZ" "UTC0") + +;;; Import private procedures. +(define make-schedule (@@ (mcron base) make-schedule)) +(define schedule-current (@@ (mcron base) schedule-current)) +(define schedule-user (@@ (mcron base) schedule-user)) +(define schedule-system (@@ (mcron base) schedule-system)) +(define make-job (@@ (mcron base) make-job)) +(define find-next-jobs (@@ (mcron base) find-next-jobs)) + +(define %user0 #("user0" "x" 0 0 "user0" "/var/empty" "/bin/sh")) +(define %user1 #("user1" "x" 1 1 "user1" "/var/empty" "/bin/sh")) + +(define* (make-dummy-job #:optional (displayable "dummy") + #:key + (user (getpw)) + (time-proc 1+) + (action (λ () "dummy action")) + (environment '()) + (next-time 0)) + (make-job user time-proc action environment displayable next-time)) + +;;; Check 'use-system-job-list' and 'use-user-job-list' effect +(let ((schdl (make-schedule '() '() 'user))) + (use-system-job-list #:schedule schdl) + (test-eq "use-system-job-list" + 'system + (schedule-current schdl)) + + (use-user-job-list #:schedule schdl) + (test-eq "use-user-job-list" + 'user + (schedule-current schdl))) + +;;; Check that 'remove-user-jobs' with only one type of user job clears the +;;; schedule. +(let* ((job (make-dummy-job #:user %user0)) + (schdl (make-schedule (list job) '() 'user))) + (remove-user-jobs %user0 #:schedule schdl) + (test-equal "remove-user-jobs: only one" + '() + (schedule-user schdl))) + +;;; Check that 'remove-user-jobs' with only two types of user jobs keep the +;;; other user jobs in the schedule. +(let* ((job0 (make-dummy-job #:user %user0)) + (job1 (make-dummy-job #:user %user1)) + (schdl (make-schedule (list job0 job1) '() 'user))) + (remove-user-jobs %user0 #:schedule schdl) + (test-equal "remove-user-jobs: keep one" + (list job1) + (schedule-user schdl))) + +;;; Check that 'clear-system-jobs' removes all system jobs and has no effect +;;; on the user jobs. +(let* ((job0 (make-dummy-job #:user %user0)) + (job1 (make-dummy-job #:user %user1)) + (schdl (make-schedule (list job0) (list job1) 'user))) + (clear-system-jobs #:schedule schdl) + (test-assert "clear-system-jobs: basic" + (and (equal? (list job0) (schedule-user schdl)) + (equal? '() (schedule-system schdl))))) + +;;; Check that 'add-job' adds a user job when the current schedule is 'user. +(let ((schdl (make-schedule '() '() 'user))) + (add-job 1+ (const #t) "job0" 0 "user" #:schedule schdl) + (test-assert "add-job: user schedule" + (and (= 1 (length (schedule-user schdl))) + (= 0 (length (schedule-system schdl)))))) + +;;; Check that 'add-job' adds a system job when the current schedule is +;;; 'system. +(let ((schdl (make-schedule '() '() 'system))) + (add-job 1+ (const #t) "job0" 0 "user" #:schedule schdl) + (test-assert "add-job: system schedule" + (and (= 0 (length (schedule-user schdl))) + (= 1 (length (schedule-system schdl)))))) + +;;; Check that 'find-next-jobs' find the soonest job. +(let* ((job0 (make-dummy-job #:user %user0 #:next-time 5)) + (job1 (make-dummy-job #:user %user1 #:next-time 10)) + (schdl (make-schedule (list job0) (list job1) 'user))) + (test-equal "find-next-jobs: basic" + (list 5 job0) + (find-next-jobs #:schedule schdl))) + +;;; Check that 'find-next-jobs' can find multiple soonest jobs. +(let* ((job0 (make-dummy-job #:user %user0 #:next-time 5)) + (job1 (make-dummy-job #:user %user1 #:next-time 5)) + (schdl (make-schedule (list job0) (list job1) 'user))) + (test-equal "find-next-jobs: two jobs" + (list 5 job0 job1) + (find-next-jobs #:schedule schdl))) + +;;; Check that 'find-next-jobs' returns #f when the schedule is empty. +(let ((schdl (make-schedule '() '() 'user))) + (test-equal "find-next-jobs: empty" + (list #f) + (find-next-jobs #:schedule schdl))) + +;;; Check output of 'display-schedule' with a basic schedule. +(test-assert "display-schedule: basic" + (and (equal? + "Thu Jan 1 00:00:05 1970 +0000\ndummy\n\n" + (let* ((job0 (make-dummy-job #:user %user0 #:next-time 5)) + (job1 (make-dummy-job #:user %user1 #:next-time 10)) + (schdl (make-schedule (list job0) (list job1) 'user))) + (with-output-to-string + (λ () (display-schedule 1 #:schedule schdl))))) + (equal? + (string-append + "Thu Jan 1 00:00:05 1970 +0000\ndummy\n\n" + "Thu Jan 1 00:00:06 1970 +0000\ndummy\n\n") + (let* ((job0 (make-dummy-job #:user %user0 #:next-time 5)) + (job1 (make-dummy-job #:user %user1 #:next-time 10)) + (schdl (make-schedule (list job0) (list job1) 'user))) + (with-output-to-string + (λ () (display-schedule 2 #:schedule schdl))))))) + +;;; Check output of 'display-schedule' with an empty schedule. +(let ((schdl (make-schedule '() '() 'user))) + (test-equal "display-schedule: empty" + "" + (with-output-to-string + (λ () (display-schedule 1 #:schedule schdl))))) + +(test-end) From 07017255a181114a9b1529aaa197e16b305910ba Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 24 Mar 2018 01:03:08 +0100 Subject: [PATCH 168/239] base: Rewrite 'find-next-jobs' docstring. * src/mcron/base.scm (find-next-jobs): Don't explain the detail of implementation in the docstring. --- src/mcron/base.scm | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/mcron/base.scm b/src/mcron/base.scm index 5cfc92c..8a3f5c3 100644 --- a/src/mcron/base.scm +++ b/src/mcron/base.scm @@ -115,21 +115,10 @@ SCHEDULE." (cons entry (schedule-system schedule)))))) (define* (find-next-jobs #:key (schedule %global-schedule)) - "Procedure to locate the jobs in SCHEDULE with the lowest (soonest) -next-times. These are the jobs for which we must schedule the mcron -program (under any personality) to next wake up. The return value is a cons -cell consisting of the next time (maintained in the next-time variable) and a -list of the job entries that are to run at this time (maintained in the -next-jobs-list variable). - -The procedure works by first obtaining the time of the first job on the list, -and setting this job in the next-jobs-list. Then for each other entry on the -job-list, either the job runs earlier than any other that have been scanned, -in which case the next-time and next-jobs-list are re-initialized to -accomodate, or the job runs at the same time as the next job, in which case -the next-jobs-list is simply augmented with the new job, or else the job runs -later than others noted in which case we ignore it for now and continue to -recurse the list." + "Locate the jobs in SCHEDULE with the lowest (soonest) next-times. Return a +list where the head is the next scheduled time and the rest are all the job +entries that are to run at this time. When SCHEDULE is empty next time is +'#f'." (let loop ((jobs (append (schedule-system schedule) (schedule-user schedule))) (next-time (inf)) From a1f9e3d7a765e7a057b6c2292cb0ccebe0c697d5 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 24 Mar 2018 01:33:22 +0100 Subject: [PATCH 169/239] utils: Add 'get-user' * src/mcron/utils.scm (get-user): New procedure. * src/mcron/job-specifier.scm (job): Use it. * src/mcron/base.scm (remove-user-jobs): Likewise. --- src/mcron/base.scm | 5 ++--- src/mcron/job-specifier.scm | 7 +++---- src/mcron/utils.scm | 13 ++++++++++++- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/mcron/base.scm b/src/mcron/base.scm index 8a3f5c3..951c1d7 100644 --- a/src/mcron/base.scm +++ b/src/mcron/base.scm @@ -28,6 +28,7 @@ (define-module (mcron base) #:use-module (ice-9 match) #:use-module (mcron environment) + #:use-module (mcron utils) #:use-module (srfi srfi-1) #:use-module (srfi srfi-2) #:use-module (srfi srfi-9) @@ -85,9 +86,7 @@ This procedure is deprecated." (define* (remove-user-jobs user #:key (schedule %global-schedule)) "Remove user jobs from SCHEDULE belonging to USER. USER must be either a username, a UID, or a passwd entry." - (let ((user* (if (or (string? user) (integer? user)) - (getpw user) - user))) + (let ((user* (get-user user))) (set-schedule-user! schedule (filter (lambda (job) (not (eqv? (passwd:uid user*) diff --git a/src/mcron/job-specifier.scm b/src/mcron/job-specifier.scm index d5bf590..5c8e171 100644 --- a/src/mcron/job-specifier.scm +++ b/src/mcron/job-specifier.scm @@ -1,6 +1,6 @@ ;;;; job-specifier.scm -- public interface for defining jobs ;;; Copyright © 2003 Dale Mellor -;;; Copyright © 2016, 2017 Mathieu Lirzin +;;; Copyright © 2016, 2017, 2018 Mathieu Lirzin ;;; ;;; This file is part of GNU Mcron. ;;; @@ -30,6 +30,7 @@ #:use-module (ice-9 match) #:use-module (mcron base) #:use-module (mcron environment) + #:use-module (mcron utils) #:use-module (mcron vixie-time) #:use-module (srfi srfi-1) #:re-export (append-environment-mods) @@ -241,9 +242,7 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." ((procedure? action) "Lambda function") ((string? action) action) ((list? action) (simple-format #f "~A" action)))) - (user* (if (or (string? user) (integer? user)) - (getpw user) - user))) + (user* (get-user user))) (add-job (lambda (current-time) (parameterize ((%current-action-time current-time)) ;; Allow for daylight savings time changes. diff --git a/src/mcron/utils.scm b/src/mcron/utils.scm index bb23f4a..98afaf0 100644 --- a/src/mcron/utils.scm +++ b/src/mcron/utils.scm @@ -29,7 +29,8 @@ parse-args show-version show-package-information - process-update-request) + process-update-request + get-user) #:re-export (option-ref read-string)) @@ -101,3 +102,13 @@ comes in on the above socket." (remove-user-jobs user) (set-configuration-user user) (read-vixie-file (string-append config-spool-dir "/" user-name))))))) + +(define (get-user spec) + "Return the passwd entry corresponding to SPEC. If SPEC is passwd entry +then return it. If SPEC is not a valid specification throw an exception." + (cond ((or (string? spec) (integer? spec)) + (getpw spec)) + ((vector? spec) ;assume a user passwd entry + spec) + (else + (throw 'invalid-user-specification spec)))) From d63db1ce4e8b30459bd3e67da619531f2741f9bf Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 24 Mar 2018 01:58:42 +0100 Subject: [PATCH 170/239] base: Rewrite 'child-cleanup' * src/mcron/base.scm (child-cleanup): Use recursion instead of 'do'. --- src/mcron/base.scm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mcron/base.scm b/src/mcron/base.scm index 951c1d7..2f1c060 100644 --- a/src/mcron/base.scm +++ b/src/mcron/base.scm @@ -182,13 +182,13 @@ next value." (job:next-time-set! job ((job:next-time-function job) (current-time)))))) -;; Give any zombie children a chance to die, and decrease the number known to -;; exist. - (define (child-cleanup) - (do () ((or (<= number-children 0) - (eqv? (car (waitpid WAIT_ANY WNOHANG)) 0))) - (set! number-children (- number-children 1)))) + ;; Give any zombie children a chance to die, and decrease the number known + ;; to exist. + (unless (or (<= number-children 0) + (= (car (waitpid WAIT_ANY WNOHANG)) 0)) + (set! number-children (- number-children 1)) + (child-cleanup))) (define* (run-job-loop #:optional fd-list #:key (schedule %global-schedule)) ;; Loop over all job specifications, get a list of the next ones to run (may From 526ce502e5b7bce1e3577696b2c41564f7248920 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 24 Mar 2018 14:03:54 +0100 Subject: [PATCH 171/239] base: Box 'number-children' * src/mcron/base.scm (number-children): Box it using SRFI-111 to be explicit about the mutability of this object. (update-number-children!): New procedure. (run-job, child-cleanup): Use it. * tests/base.scm ("update-number-children!: 1+") ("number-children: init", "update-number-children!: 1-"): New tests. --- src/mcron/base.scm | 21 +++++++++++++++------ tests/base.scm | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/mcron/base.scm b/src/mcron/base.scm index 2f1c060..17ddd5c 100644 --- a/src/mcron/base.scm +++ b/src/mcron/base.scm @@ -32,6 +32,7 @@ #:use-module (srfi srfi-1) #:use-module (srfi srfi-2) #:use-module (srfi srfi-9) + #:use-module (srfi srfi-111) #:export (add-job remove-user-jobs display-schedule @@ -157,10 +158,18 @@ unusable." jobs)))) (display-schedule (- count 1) port #:schedule schedule))) -;; For proper housekeeping, it is necessary to keep a record of the number of -;; child processes we fork off to run the jobs. +;;; +;;; Running jobs +;;; -(define number-children 0) +(define number-children + ;; For proper housekeeping, it is necessary to keep a record of the number + ;; of child processes we fork off to run the jobs. + (box 0)) + +(define (update-number-children! proc) + ;; Apply PROC to the value stored in 'number-children'. + (set-box! number-children (proc (unbox number-children)))) (define (run-job job) "Run JOB in a separate process. The process is run as JOB user with the @@ -178,16 +187,16 @@ next value." (λ () (primitive-exit 0))) (begin ;parent - (set! number-children (+ number-children 1)) + (update-number-children! 1+) (job:next-time-set! job ((job:next-time-function job) (current-time)))))) (define (child-cleanup) ;; Give any zombie children a chance to die, and decrease the number known ;; to exist. - (unless (or (<= number-children 0) + (unless (or (<= (unbox number-children) 0) (= (car (waitpid WAIT_ANY WNOHANG)) 0)) - (set! number-children (- number-children 1)) + (update-number-children! 1-) (child-cleanup))) (define* (run-job-loop #:optional fd-list #:key (schedule %global-schedule)) diff --git a/tests/base.scm b/tests/base.scm index 89b7349..d7a2dbd 100644 --- a/tests/base.scm +++ b/tests/base.scm @@ -17,6 +17,7 @@ ;;; along with GNU Mcron. If not, see . (use-modules (srfi srfi-64) + (srfi srfi-111) (mcron base)) (test-begin "base") @@ -148,4 +149,35 @@ (with-output-to-string (λ () (display-schedule 1 #:schedule schdl))))) +;;; +;;; Running jobs +;;; + +;;; Import private global. +(define number-children (@@ (mcron base) number-children)) + +;;; Import private procedures. +(define update-number-children! (@@ (mcron base) update-number-children!)) + +;;; Check 'number-children' initial value. +(let ((schdl (make-schedule '() '() 'user))) + (test-equal "number-children: init" + 0 + (unbox number-children))) + +;;; Check 'update-number-children!' incrementation. +(let ((schdl (make-schedule '() '() 'user))) + (update-number-children! 1+) + (update-number-children! 1+) + (test-equal "update-number-children!: 1+" + 2 + (unbox number-children))) + +;;; Check 'update-number-children!' decrementation. +(let ((schdl (make-schedule '() '() 'user))) + (update-number-children! 1-) + (test-equal "update-number-children!: 1-" + 1 + (unbox number-children))) + (test-end) From d1e0d2a8f75b28286986fce7c0e8cfe552cde322 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 24 Mar 2018 15:28:36 +0100 Subject: [PATCH 172/239] base: Check 'run-job' * tests/base.scm ("run-job: basic"): New test. --- tests/base.scm | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/base.scm b/tests/base.scm index d7a2dbd..164f364 100644 --- a/tests/base.scm +++ b/tests/base.scm @@ -158,6 +158,7 @@ ;;; Import private procedures. (define update-number-children! (@@ (mcron base) update-number-children!)) +(define run-job (@@ (mcron base) run-job)) ;;; Check 'number-children' initial value. (let ((schdl (make-schedule '() '() 'user))) @@ -180,4 +181,19 @@ 1 (unbox number-children))) +;;; Check 'run-job' basic call. +;;; XXX: Having to use the filesystem for a unit test is wrong. +(let* ((filename (tmpnam)) + (action (λ () (close-port (open-output-file filename)))) + (job (make-dummy-job #:user (getpw (getuid)) #:action action))) + (dynamic-wind + (λ () + (run-job job) + (waitpid WAIT_ANY)) + (λ () + (test-assert "run-job: basic" + (access? filename F_OK))) + (λ () + (delete-file filename)))) + (test-end) From e013e2a6d64da700a3a096e2dbb5ff6856f97697 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 24 Mar 2018 20:10:04 +0100 Subject: [PATCH 173/239] environment: Refactor configuration environment handling * src/mcron/environment.scm (current-environment-mods): Rename to ... (%current-environment-mods): ... this. Box it using SRFI-111 to be explicit about the mutability of this object. (get-current-environment-mods-copy, clear-environment-mods) (append-environment-mods): New '#:ENVIRON' argument. --- src/mcron/environment.scm | 67 ++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/mcron/environment.scm b/src/mcron/environment.scm index f6b9637..469f6f5 100644 --- a/src/mcron/environment.scm +++ b/src/mcron/environment.scm @@ -1,6 +1,6 @@ ;;;; environment.scm -- interact with the job process environment ;;; Copyright © 2003 Dale Mellor -;;; Copyright © 2015, 2016 Mathieu Lirzin +;;; Copyright © 2015, 2016, 2018 Mathieu Lirzin ;;; ;;; This file is part of GNU Mcron. ;;; @@ -32,48 +32,51 @@ ;;;; Code: (define-module (mcron environment) + #:use-module (srfi srfi-111) #:export (modify-environment clear-environment-mods append-environment-mods get-current-environment-mods-copy)) - +;;; +;;; Configuration files +;;; -;; As we parse configuration files, we build up an alist of environment -;; variables here. +(define %current-environment-mods + ;; Global variable containing an alist of environment variables populated as + ;; we parse configuration files. + (box '())) -(define current-environment-mods '()) +(define* (get-current-environment-mods-copy + #:key (environ %current-environment-mods)) + "Return a snapshot of the current environment modifications from ENVIRON. +This snapshot is a copy of the environment so that modifying it doesn't +impact ENVIRON." + ;; Each time a job is registered we should call this procedure. + (list-copy (unbox environ))) +(define* (clear-environment-mods #:key (environ %current-environment-mods)) + "Remove all entries in the ENVIRON environment." + ;; When we start to parse a new configuration file, we want to start with a + ;; fresh environment (actually an umodified version of the pervading mcron + ;; environment) by calling this procedure. + (set-box! environ '())) - -;; Each time a job is added to the system, we take a snapshot of the current -;; set of environment modifiers. - -(define (get-current-environment-mods-copy) - (list-copy current-environment-mods)) - - - -;; When we start to parse a new configuration file, we want to start with a -;; fresh environment (actually an umodified version of the pervading mcron -;; environment). - -(define (clear-environment-mods) - (set! current-environment-mods '())) - - - -;; Procedure to add another environment setting to the alist above. This is -;; used both implicitly by the Vixie parser, and can be used directly by users -;; in scheme configuration files. The return value is purely for the -;; convenience of the parse-vixie-environment in the vixie-specification module -;; (yuk). - -(define (append-environment-mods name value) - (set! current-environment-mods (append current-environment-mods - (list (cons name value)))) +(define* (append-environment-mods name value + #:key (environ %current-environment-mods)) + "Set NAME to VALUE in the ENVIRON environment. If VALUES is #f then NAME is +considered unset." + ;; This procedure is used implicitly by the Vixie parser, and can be used + ;; directly by users in scheme configuration files. + (set-box! environ (append (unbox environ) `((,name . ,value)))) + ;; XXX: The return value is purely for the convenience of the + ;; '(@ (mcron vixie-specification) parse-vixie-environment)'. #t) +;;; +;;; Job runtime +;;; + (define (modify-environment env passwd-entry) "Modify the environment (in the UNIX sense) by setting the variables from ENV and some default ones which are modulated by PASSWD-ENTRY. \"LOGNAME\" From b8cbf635cc4dad9be860d4489ba8e9a308082c3d Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 24 Mar 2018 20:23:45 +0100 Subject: [PATCH 174/239] environment: Check configuration environment * tests/environment.scm ("current-environment-mods-copy: empty") ("current-environment-mods: init", "append-environment-mods: basic") ("append-environment-mods: twice", "clear-environment-mods: effect") ("current-environment-mods-copy: basic"): New tests. --- tests/environment.scm | 55 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/tests/environment.scm b/tests/environment.scm index 1bc34a6..05ad3be 100644 --- a/tests/environment.scm +++ b/tests/environment.scm @@ -1,5 +1,5 @@ ;;;; environment.scm -- tests for (mcron environment) module -;;; Copyright © 2016 Mathieu Lirzin +;;; Copyright © 2016, 2018 Mathieu Lirzin ;;; ;;; This file is part of GNU Mcron. ;;; @@ -17,10 +17,63 @@ ;;; along with GNU Mcron. If not, see . (use-modules (srfi srfi-64) + (srfi srfi-111) (mcron environment)) (test-begin "environment") +;;; Check 'current-environment-mods' initial value which should be empty. +(test-equal "current-environment-mods: init" + '() + (unbox (@@ (mcron environment) %current-environment-mods))) + +;;; Check 'current-environment-mods-copy' with an empty environment +(test-assert "current-environment-mods-copy: empty" + (let* ((env (box '())) + (copy0 (get-current-environment-mods-copy #:environ env)) + (copy1 (get-current-environment-mods-copy #:environ env))) + (set! copy1 (assoc-set! copy1 "FOO" "BAR")) + (and (equal? '() (unbox env)) + (equal? '() copy0) + (equal? '(("FOO" . "BAR")) copy1)))) + +;;; Check 'current-environment-mods-copy' with a basic environment +(test-assert "current-environment-mods-copy: basic" + (let* ((init-env '(("a" . "1") ("b" . "2"))) + (env (box init-env)) + (copy0 (get-current-environment-mods-copy #:environ env)) + (copy1 (get-current-environment-mods-copy #:environ env))) + (set! copy1 (assoc-set! copy1 "c" "3")) + (and (equal? init-env (unbox env)) + (equal? init-env copy0) + (equal? `(("c" . "3") . ,init-env) copy1)))) + +;;; Check 'append-environment-mods' basic call +(test-equal "append-environment-mods: basic" + "BAR" + (let ((env (box '()))) + (append-environment-mods "FOO" "BAR" #:environ env) + (assoc-ref (unbox env) "FOO"))) + +;;; Check 'append-environment-mods' that when adding the same key twice the +;;; later is placed after the previous one. +(test-equal "append-environment-mods: twice" + '(("FOO" . "BAR") ("FOO" . "BAZ")) + (let ((env (box '()))) + (append-environment-mods "FOO" "BAR" #:environ env) + (append-environment-mods "FOO" "BAZ" #:environ env) + (unbox env))) + +;;; Check 'clear-environment-mods' side effect +(test-equal "clear-environment-mods: effect" + '() + (let ((env (box '()))) + (append-environment-mods "FOO" "BAR" #:environ env) + (append-environment-mods "FOO" "BAZ" #:environ env) + (clear-environment-mods #:environ env) + (unbox env))) + +;;; Check 'modify-environment' basic call (test-assert "modifiy-environment: basic" (begin (modify-environment '(("FOO" . "bar")) (getpw)) From 0159423d15f882d9e44edd1a51dc13314c25e15b Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 24 Mar 2018 21:13:51 +0100 Subject: [PATCH 175/239] tests: Remove unused schedule stubs * tests/base.scm ("number-children: init") ("update-number-children!: 1+", "update-number-children!: 1-"): Remove 'let' form defining the schedule stub. --- tests/base.scm | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/tests/base.scm b/tests/base.scm index 164f364..39e35fd 100644 --- a/tests/base.scm +++ b/tests/base.scm @@ -161,24 +161,23 @@ (define run-job (@@ (mcron base) run-job)) ;;; Check 'number-children' initial value. -(let ((schdl (make-schedule '() '() 'user))) - (test-equal "number-children: init" - 0 - (unbox number-children))) +(test-equal "number-children: init" + 0 + (unbox number-children)) ;;; Check 'update-number-children!' incrementation. -(let ((schdl (make-schedule '() '() 'user))) - (update-number-children! 1+) - (update-number-children! 1+) - (test-equal "update-number-children!: 1+" - 2 +(test-equal "update-number-children!: 1+" + 2 + (begin + (update-number-children! 1+) + (update-number-children! 1+) (unbox number-children))) ;;; Check 'update-number-children!' decrementation. -(let ((schdl (make-schedule '() '() 'user))) - (update-number-children! 1-) - (test-equal "update-number-children!: 1-" - 1 +(test-equal "update-number-children!: 1-" + 1 + (begin + (update-number-children! 1-) (unbox number-children))) ;;; Check 'run-job' basic call. From a8511ce35d33e408de5dd16bc1e1ff9bb2e606cf Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 24 Mar 2018 22:06:44 +0100 Subject: [PATCH 176/239] maint: Add "build-aux/gnu-fetch" script. * build-aux/gnu-fetch: New script for fetching auxilary scripts maintained in other GNU repositories. * HACKING: Document how to run it. --- HACKING | 8 +++- build-aux/gnu-fetch | 97 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100755 build-aux/gnu-fetch diff --git a/HACKING b/HACKING index a9e9f5a..039e9d1 100644 --- a/HACKING +++ b/HACKING @@ -52,10 +52,16 @@ follows. Run the command "git format-patch --stdout -1", and email its output in, using the output's subject line. +* Updating auxilary scripts + + Fetch new versions of the files that are maintained in other GNU + repositories by running "cd build-aux; ./gnu-fetch". In case any file in the + Mcron repository has been updated, commit and re-run the testsuite. + ----- Copyright © 2002-2017 Free Software Foundation, Inc. -Copyright © 2017 Mathieu Lirzin +Copyright © 2017, 2018 Mathieu Lirzin This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/build-aux/gnu-fetch b/build-aux/gnu-fetch new file mode 100755 index 0000000..5655b16 --- /dev/null +++ b/build-aux/gnu-fetch @@ -0,0 +1,97 @@ +#!/bin/sh +# Fetch files maintained in other GNU repositories. + +scriptversion=2018-03-24.21; # UTC + +# Copyright © 2018 Mathieu Lirzin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set -e + +WGET=wget + +# Git repositories on Savannah. +git_sv_host='git.savannah.gnu.org' + +# Some repositories we sync files from. +sv_git_am="https://${git_sv_host}/gitweb/?p=automake.git;a=blob_plain;hb=HEAD;f=" +sv_git_gl="https://${git_sv_host}/gitweb/?p=gnulib.git;a=blob_plain;hb=HEAD;f=" + +# Files that we fetch and which we compare against. +# Note that the 'lib/COPYING' file must still be synced by hand. +FETCHFILES=" + ${sv_git_am}contrib/test-driver.scm + ${sv_git_gl}build-aux/gitlog-to-changelog + ${sv_git_gl}build-aux/do-release-commit-and-tag + ${sv_git_gl}build-aux/gnu-web-doc-update + ${sv_git_gl}build-aux/gnupload +" + +usage="Usage: $0 + +fetch files maintained in other GNU repositories +" + +while test -n "$1" +do + case $1 in + -*) + case $1 in + --help) + echo "$usage" + exit $? + ;; + --version) + echo "gnu-fetch $scriptversion" + exit $? + ;; + --) + shift + break + ;; + -*) + echo "$0: Unknown option '$1', try '$0 --help'" 1>&2 + exit 1 + ;; + esac + ;; + esac + shift +done + +rm -rf Fetchdir +mkdir Fetchdir +for url in ${FETCHFILES} +do + file=`printf '%s\n' "$url" | sed 's|^.*/||; s|^.*=||'` + "$WGET" -nv "$url" -O "Fetchdir/$file" || exit 1 + if cmp "Fetchdir/$file" "$file" >/dev/null; then + : Nothing to do + else + echo "$0: updating file $file" + cp "Fetchdir/$file" "$file" || exit 1 + fi +done +rm -rf Fetchdir + +exit 0 + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: From 2169f4a7b349f34fc175412668098db3859493e2 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 24 Mar 2018 22:09:15 +0100 Subject: [PATCH 177/239] maint: Update files from upstream with "build-aux/gnu-fetch" * build-aux/gitlog-to-changelog: Update. * build-aux/test-driver.scm: Likewise. --- build-aux/gitlog-to-changelog | 33 +++++---- build-aux/test-driver.scm | 124 ++++++++++++++++++++-------------- 2 files changed, 92 insertions(+), 65 deletions(-) diff --git a/build-aux/gitlog-to-changelog b/build-aux/gitlog-to-changelog index 8f38318..1e73f42 100755 --- a/build-aux/gitlog-to-changelog +++ b/build-aux/gitlog-to-changelog @@ -1,15 +1,15 @@ -eval '(exit $?0)' && eval 'exec perl -wS "$0" ${1+"$@"}' +eval '(exit $?0)' && eval 'exec perl -wS "$0" "$@"' & eval 'exec perl -wS "$0" $argv:q' if 0; # Convert git log output to ChangeLog format. -my $VERSION = '2015-07-21 22:45'; # UTC +my $VERSION = '2018-03-07 03:47'; # UTC # The definition above must lie within the first 8 lines in order # for the Emacs time-stamp write hook (at end) to update it. # If you change this file with Emacs, please let the write hook # do its job. Otherwise, update this string manually. -# Copyright (C) 2008-2015 Free Software Foundation, Inc. +# Copyright (C) 2008-2018 Free Software Foundation, Inc. # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -22,7 +22,7 @@ my $VERSION = '2015-07-21 22:45'; # UTC # GNU General Public License for more details. # You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# along with this program. If not, see . # Written by Jim Meyering @@ -33,7 +33,7 @@ use POSIX qw(strftime); (my $ME = $0) =~ s|.*/||; -# use File::Coda; # http://meyering.net/code/Coda/ +# use File::Coda; # https://meyering.net/code/Coda/ END { defined fileno STDOUT or return; close STDOUT and return; @@ -298,9 +298,7 @@ sub git_dir_option($) { if ($sha =~ /^$_/) { - $skipflag = 1; - ## Perhaps only warn if a pattern matches more than once? - warn "$ME: warning: skipping $sha due to $_\n"; + $skipflag = $_; last; } } @@ -333,7 +331,7 @@ sub git_dir_option($) $rest =~ s/^\s*\(cherry picked from commit [\da-f]+\)\n//m; } - my @line = split /\s*\n/, $rest; + my @line = split /[ \t]*\n/, $rest; my $author_line = shift @line; defined $author_line or die "$ME:$.: unexpected EOF\n"; @@ -386,8 +384,17 @@ sub git_dir_option($) } # Ignore commits that match the --ignore-matching pattern, if specified. - if (! ($skipflag || (defined $ignore_matching - && @line && $line[0] =~ /$ignore_matching/))) + if (defined $ignore_matching && @line && $line[0] =~ /$ignore_matching/) + { + $skipflag = 1; + } + elsif ($skipflag) + { + ## Perhaps only warn if a pattern matches more than once? + warn "$ME: warning: skipping $sha due to $skipflag\n"; + } + + if (! $skipflag) { if (defined $ignore_line && @line) { @@ -484,9 +491,9 @@ sub git_dir_option($) # Local Variables: # mode: perl # indent-tabs-mode: nil -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "my $VERSION = '" # time-stamp-format: "%:y-%02m-%02d %02H:%02M" -# time-stamp-time-zone: "UTC" +# time-stamp-time-zone: "UTC0" # time-stamp-end: "'; # UTC" # End: diff --git a/build-aux/test-driver.scm b/build-aux/test-driver.scm index 01edf93..5292c0a 100644 --- a/build-aux/test-driver.scm +++ b/build-aux/test-driver.scm @@ -1,8 +1,8 @@ ;;;; test-driver.scm - Guile test driver for Automake testsuite harness -(define script-version "2016-05-09.22") ;UTC +(define script-version "2018-03-24.22") ;UTC -;;; Copyright (C) 2015, 2016 Mathieu Lirzin +;;; Copyright © 2015-2018 Free Software Foundation, Inc. ;;; ;;; This program is free software; you can redistribute it and/or modify it ;;; under the terms of the GNU General Public License as published by @@ -16,20 +16,40 @@ ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with this program. If not, see . -;;; -;;; As a special exception to the GNU General Public License, if you -;;; distribute this file as part of a program that contains a configuration -;;; script generated by Autoconf, you may include it under the same -;;; distribution terms that you use for the rest of that program. ;;;; Commentary: ;;; ;;; This script provides a Guile test driver using the SRFI-64 Scheme API for ;;; test suites. SRFI-64 is distributed with Guile since version 2.0.9. ;;; +;;; To use it, you have to manually copy this file in the ‘build-aux’ +;;; directory of your package, then adapt the following snippets to your +;;; actual needs: +;;; +;;; configure.ac: +;;; AC_CONFIG_AUX_DIR([build-aux]) +;;; AC_REQUIRE_AUX_FILE([test-driver.scm]) +;;; AC_PATH_PROG([GUILE], [guile]) +;;; +;;; Makefile.am +;;; TEST_LOG_DRIVER = $(GUILE) $(top_srcdir)/build-aux/test-driver.scm +;;; AM_TESTS_ENVIRONMENT = env GUILE_AUTO_COMPILE='0' +;;; TESTS = foo.test +;;; EXTRA_DIST = $(TESTS) +;;; +;;; foo.test +;;; (use-modules (srfi srfi-64)) +;;; (test-begin "foo") +;;; (test-assert "assertion example" #t) +;;; (test-end "foo") +;;; +;;; See for general +;;; information about SRFI-64 usage. +;;; ;;;; Code: (use-modules (ice-9 getopt-long) + (ice-9 match) (ice-9 pretty-print) (srfi srfi-26) (srfi srfi-64)) @@ -64,7 +84,7 @@ The '--test-name', '--log-file' and '--trs-file' options are mandatory.\n")) (begin (format port "~A:~%" field) (pretty-print value port #:per-line-prefix "+ ")) - (format port "~A: ~A~%" field value))) + (format port "~A: ~S~%" field value))) (define* (result->string symbol #:key colorize?) "Return SYMBOL as an upper case string. Use colors when COLORIZE is #t." @@ -90,10 +110,10 @@ current output port is supposed to be redirected to a '.log' file." ;; Procedure called at the start of an individual test case, before the ;; test expression (and expected value) are evaluated. (let ((result (cute assq-ref (test-result-alist runner) <>))) - (test-display "test-name" (result 'test-name)) - (test-display "location" - (string-append (result 'source-file) ":" - (number->string (result 'source-line)))) + (format #t "test-name: ~A~%" (result 'test-name)) + (format #t "location: ~A~%" + (string-append (result 'source-file) ":" + (number->string (result 'source-line)))) (test-display "source" (result 'source-form) #:pretty? #t))) (define (test-on-test-end-gnu runner) @@ -104,10 +124,9 @@ current output port is supposed to be redirected to a '.log' file." (result (cut assq-ref results <>))) (unless brief? ;; Display the result of each test case on the console. - (test-display - (result->string (test-result-kind runner) #:colorize? color?) - (string-append test-name " - " (test-runner-test-name runner)) - out-port)) + (format out-port "~A: ~A - ~A~%" + (result->string (test-result-kind runner) #:colorize? color?) + test-name (test-runner-test-name runner))) (when (result? 'expected-value) (test-display "expected-value" (result 'expected-value))) (when (result? 'expected-error) @@ -116,12 +135,11 @@ current output port is supposed to be redirected to a '.log' file." (test-display "actual-value" (result 'actual-value))) (when (result? 'actual-error) (test-display "actual-error" (result 'actual-error) #:pretty? #t)) - (test-display "result" (result->string (result 'result-kind))) + (format #t "result: ~a~%" (result->string (result 'result-kind))) (newline) - (test-display ":test-result" - (string-append (result->string (test-result-kind runner)) - " " (test-runner-test-name runner)) - trs-port))) + (format trs-port ":test-result: ~A ~A~%" + (result->string (test-result-kind runner)) + (test-runner-test-name runner)))) (define (test-on-group-end-gnu runner) ;; Procedure called by a 'test-end', including at the end of a test-group. @@ -130,21 +148,18 @@ current output port is supposed to be redirected to a '.log' file." (skip (or (positive? (test-runner-skip-count runner)) (positive? (test-runner-xfail-count runner))))) ;; XXX: The global results need some refinements for XPASS. - (test-display ":global-test-result" - (if fail "FAIL" (if skip "SKIP" "PASS")) - trs-port) - (test-display ":recheck" - (if fail "yes" "no") - trs-port) - (test-display ":copy-in-global-log" - (if (or fail skip) "yes" "no") - trs-port) + (format trs-port ":global-test-result: ~A~%" + (if fail "FAIL" (if skip "SKIP" "PASS"))) + (format trs-port ":recheck: ~A~%" + (if fail "yes" "no")) + (format trs-port ":copy-in-global-log: ~A~%" + (if (or fail skip) "yes" "no")) (when brief? ;; Display the global test group result on the console. - (test-display (result->string (if fail 'fail (if skip 'skip 'pass)) - #:colorize? color?) - test-name - out-port)) + (format out-port "~A: ~A~%" + (result->string (if fail 'fail (if skip 'skip 'pass)) + #:colorize? color?) + test-name)) #f)) (let ((runner (test-runner-null))) @@ -163,30 +178,35 @@ current output port is supposed to be redirected to a '.log' file." (option (cut option-ref opts <> <>))) (cond ((option 'help #f) (show-help)) - ((option 'version #f) (format #t "test-driver.scm ~A~%" script-version)) + ((option 'version #f) (format #t "test-driver.scm ~A" script-version)) (else - (let ((log (open-file (option 'log-file "") "w0")) - (trs (open-file (option 'trs-file "") "wl")) - (out (duplicate-port (current-output-port) "wl"))) - (redirect-port log (current-output-port)) - (redirect-port log (current-warning-port)) - (redirect-port log (current-error-port)) - (test-with-runner - (test-runner-gnu (option 'test-name #f) - #:color? (option->boolean opts 'color-tests) - #:brief? (option->boolean opts 'brief) - #:out-port out #:trs-port trs) - (load (string-append (getcwd) "/" (car (option '() '("")))))) - (close-port log) - (close-port trs) - (close-port out)))) + (match (option '() '()) + (() + (display "missing test script argument\n" (current-error-port)) + (exit 1)) + ((script . args) + (let ((log (open-file (option 'log-file "") "w0")) + (trs (open-file (option 'trs-file "") "wl")) + (out (duplicate-port (current-output-port) "wl"))) + (redirect-port log (current-output-port)) + (redirect-port log (current-warning-port)) + (redirect-port log (current-error-port)) + (test-with-runner + (test-runner-gnu (option 'test-name #f) + #:color? (option->boolean opts 'color-tests) + #:brief? (option->boolean opts 'brief) + #:out-port out #:trs-port trs) + (primitive-load script)) + (close-port log) + (close-port trs) + (close-port out)))))) (exit 0)) ;;; Local Variables: -;;; eval: (add-hook 'write-file-functions 'time-stamp) +;;; eval: (add-hook 'before-save-hook 'time-stamp) ;;; time-stamp-start: "(define script-version \"" ;;; time-stamp-format: "%:y-%02m-%02d.%02H" -;;; time-stamp-time-zone: "UTC" +;;; time-stamp-time-zone: "UTC0" ;;; time-stamp-end: "\") ;UTC" ;;; End: From 5af999fb20c5bae645a5f2005f0411a1130b7455 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 25 Mar 2018 00:28:52 +0100 Subject: [PATCH 178/239] tests: Add "tests/utils.scm" * tests/utils.scm: New test. * Makefile.am (TESTS): Add it. --- Makefile.am | 3 ++- tests/utils.scm | 51 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 tests/utils.scm diff --git a/Makefile.am b/Makefile.am index 07a492f..9c7e5c1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -138,7 +138,8 @@ TESTS = \ tests/schedule.sh \ tests/base.scm \ tests/environment.scm \ - tests/job-specifier.scm + tests/job-specifier.scm \ + tests/utils.scm ## -------------- ## ## Distribution. ## diff --git a/tests/utils.scm b/tests/utils.scm new file mode 100644 index 0000000..5ec5d11 --- /dev/null +++ b/tests/utils.scm @@ -0,0 +1,51 @@ +;;;; utils.scm -- tests for (mcron utils) module +;;; Copyright © 2018 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . + +(use-modules (srfi srfi-64) + (mcron utils)) + +(test-begin "utils") + +(define entry + ;; Random user entry. + (getpw)) + +;;; Call 'get-user' with a valid uid. +(let ((uid (getuid))) + (test-equal "get-user: uid" + uid + (passwd:uid (get-user uid)))) + +;;; Call 'get-user' with a valid user name. +(let ((name (passwd:name entry))) + (test-equal "get-user: name" + name + (passwd:name (get-user name)))) + +;;; Call 'get-user' with a passwd entry. +(test-equal "get-user: passwd entry" + entry + (get-user entry)) + +;;; Call 'get-user' with an invalid uid. +(test-error "get-user: invalid uid" #t (get-user -20000)) + +;;; Call 'get-user' with an invalid spec. +(test-error "get-user: invalid spec" #t (get-user 'wrong)) + +(test-end) From 4d636af87621211354cc716e92cd9fe4e1200500 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 25 Mar 2018 03:01:45 +0200 Subject: [PATCH 179/239] utils: Check 'mcron-error' * tests/utils.scm ("mcron-error: exit code", "mcron-error: output") ("mcron-error: output no-exit", "mcron-error: only stderr"): New tests. --- tests/utils.scm | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/tests/utils.scm b/tests/utils.scm index 5ec5d11..fbd32e1 100644 --- a/tests/utils.scm +++ b/tests/utils.scm @@ -16,11 +16,53 @@ ;;; You should have received a copy of the GNU General Public License ;;; along with GNU Mcron. If not, see . -(use-modules (srfi srfi-64) +(use-modules (ice-9 match) + (ice-9 rdelim) + (srfi srfi-64) (mcron utils)) (test-begin "utils") +;;; Check 'mcron-error' error code return value. +(test-equal "mcron-error: exit code" + 42 + (match (primitive-fork) + (0 ;child + (mcron-error 42 "exit with 42")) + ((= waitpid (pid . exit-code)) ;parent + (status:exit-val exit-code)))) + +;;; Check 'mcron-error' output with basic error code. +(test-equal "mcron-error: output" + "mcron: token" + (call-with-output-string + (λ (port) + (match (pipe) + ((in . out) + (match (primitive-fork) + (0 ;child + (close in) + (with-error-to-port out + (λ () (mcron-error 37 "token")))) + ((= waitpid (pid . exit-code)) ;parent + (close out) + (display (read-line in) port)))))))) + +;;; Check mcron-error output when error code is 0. +(test-equal "mcron-error: output no-exit" + "mcron: foobar\n" + (call-with-output-string + (λ (port) + (with-error-to-port port + (λ () + (mcron-error 0 "foo" "bar")))))) + +;;; Check that mcron-error doesn't print anything on the standard output. +(test-equal "mcron-error: only stderr" + "" + (with-output-to-string + (λ () (mcron-error 0 "foo" "bar")))) + (define entry ;; Random user entry. (getpw)) From c20e4cc0aa12dc75e7aeefff6c45dabe285d954d Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 25 Mar 2018 03:09:29 +0200 Subject: [PATCH 180/239] utils: It's 2018! * src/mcron/utils.scm (show-version): Update copyright. --- src/mcron/utils.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mcron/utils.scm b/src/mcron/utils.scm index 98afaf0..da72ea5 100644 --- a/src/mcron/utils.scm +++ b/src/mcron/utils.scm @@ -66,7 +66,7 @@ and exit with its error code." (short-name (cadr (string-split name #\space))) (version config-package-version)) (simple-format #t "~a (~a) ~a -Copyright (C) 2015 the ~a authors. +Copyright (C) 2018 the ~a authors. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.\n" From 5023a8c7ca42121c3316a8e77045ff01a390ca27 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 25 Mar 2018 07:40:28 +0200 Subject: [PATCH 181/239] maint: Update files from upstream with "build-aux/gnu-fetch" * build-aux/test-driver.scm: Update. --- build-aux/test-driver.scm | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/build-aux/test-driver.scm b/build-aux/test-driver.scm index 5292c0a..e264bea 100644 --- a/build-aux/test-driver.scm +++ b/build-aux/test-driver.scm @@ -1,6 +1,6 @@ ;;;; test-driver.scm - Guile test driver for Automake testsuite harness -(define script-version "2018-03-24.22") ;UTC +(define script-version "2018-03-25.05") ;UTC ;;; Copyright © 2015-2018 Free Software Foundation, Inc. ;;; @@ -51,14 +51,18 @@ (use-modules (ice-9 getopt-long) (ice-9 match) (ice-9 pretty-print) + (srfi srfi-11) (srfi srfi-26) - (srfi srfi-64)) + (srfi srfi-64) + (system vm coverage) + (system vm vm)) (define (show-help) (display "Usage: test-driver --test-name=NAME --log-file=PATH --trs-file=PATH [--expect-failure={yes|no}] [--color-tests={yes|no}] - [--enable-hard-errors={yes|no}] [--brief={yes|no}}] [--] + [--enable-hard-errors={yes|no}] [--brief={yes|no}}] + [--coverage={yes|no}] [--] TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS] The '--test-name', '--log-file' and '--trs-file' options are mandatory.\n")) @@ -69,6 +73,7 @@ The '--test-name', '--log-file' and '--trs-file' options are mandatory.\n")) (color-tests (value #t)) (expect-failure (value #t)) ;XXX: not implemented yet (enable-hard-errors (value #t)) ;not implemented in SRFI-64 + (coverage (value #t)) (brief (value #t)) (help (single-char #\h) (value #f)) (version (single-char #\V) (value #f)))) @@ -188,15 +193,29 @@ current output port is supposed to be redirected to a '.log' file." (let ((log (open-file (option 'log-file "") "w0")) (trs (open-file (option 'trs-file "") "wl")) (out (duplicate-port (current-output-port) "wl"))) + (define (check) + (test-with-runner + (test-runner-gnu (option 'test-name #f) + #:color? (option->boolean opts 'color-tests) + #:brief? (option->boolean opts 'brief) + #:out-port out #:trs-port trs) + (primitive-load script))) + (redirect-port log (current-output-port)) (redirect-port log (current-warning-port)) (redirect-port log (current-error-port)) - (test-with-runner - (test-runner-gnu (option 'test-name #f) - #:color? (option->boolean opts 'color-tests) - #:brief? (option->boolean opts 'brief) - #:out-port out #:trs-port trs) - (primitive-load script)) + + (if (not (option->boolean opts 'coverage)) + (check) + (begin + ;; The debug engine is required for tracing coverage data. + (set-vm-engine! 'debug) + (let-values (((data result) (with-code-coverage check))) + (let* ((file (string-append (option 'test-name #f) ".info")) + (port (open-output-file file))) + (coverage-data->lcov data port) + (close port))))) + (close-port log) (close-port trs) (close-port out)))))) From 9ce38228e86f292aa612ae5c7737dfceaedceda9 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 25 Mar 2018 07:41:55 +0200 Subject: [PATCH 182/239] maint: Document how to get code coverage reports * HACKING : New section. --- HACKING | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/HACKING b/HACKING index 039e9d1..e51515c 100644 --- a/HACKING +++ b/HACKING @@ -58,6 +58,14 @@ follows. repositories by running "cd build-aux; ./gnu-fetch". In case any file in the Mcron repository has been updated, commit and re-run the testsuite. +* Code coverage + + Assuming 'lcov' is installed, it is possible to check the actual code + coverage achieved by the test suite by running the following commands: + + $ make check SCM_LOG_DRIVER_FLAGS="--coverage=yes" + $ genhtml tests/*.info --output-directory out + ----- Copyright © 2002-2017 Free Software Foundation, Inc. From 6c4f93371c7d0cd846c4b318e86f3761bf3e6e8c Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 25 Mar 2018 22:36:18 +0200 Subject: [PATCH 183/239] build: Add "maint.mk" * maint.mk: New maintainer-only Makefile fragment. * Makefile.am: Include it. * configure.ac: Substitute "maint.mk" content when it exists. --- Makefile.am | 6 ++++++ configure.ac | 6 ++++++ maint.mk | 20 ++++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 maint.mk diff --git a/Makefile.am b/Makefile.am index 9c7e5c1..d551e5d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -257,3 +257,9 @@ guilec_verbose_0 = @echo " GUILEC " $@; devnull_verbose = $(devnull_verbose_@AM_V@) devnull_verbose_ = $(devnull_verbose_@AM_DEFAULT_V@) devnull_verbose_0 = >/dev/null + +## ------------- ## +## Maintenance. ## +## ------------- ## + +@MAINT_MAKEFILE@ diff --git a/configure.ac b/configure.ac index fbda198..0bb9262 100644 --- a/configure.ac +++ b/configure.ac @@ -139,6 +139,12 @@ AC_ARG_WITH(tmp-dir, AC_MSG_RESULT($CONFIG_TMP_DIR) AC_SUBST(CONFIG_TMP_DIR) +# Include the Maintainer's Makefile fragment, if it's here. +MAINT_MAKEFILE=/dev/null +AS_IF([test -r "$srcdir/maint.mk"], + [MAINT_MAKEFILE="$srcdir/maint.mk"]) +AC_SUBST_FILE([MAINT_MAKEFILE]) + AC_CONFIG_FILES([pre-inst-env:build-aux/pre-inst-env.in], [chmod +x pre-inst-env]) AC_CONFIG_FILES([doc/config.texi diff --git a/maint.mk b/maint.mk new file mode 100644 index 0000000..791e366 --- /dev/null +++ b/maint.mk @@ -0,0 +1,20 @@ +## Maintainer-only Makefile fragment +# Copyright © 2018 Mathieu Lirzin +# +# This file is part of GNU Mcron. +# +# GNU Mcron is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNU Mcron is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Mcron. If not, see . + +# Rebuild Makefile.in if this file is modifed. +Makefile.in: maint.mk From e66f0dcdd6f1838c8d4f5d70cea7ca63dc150ead Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 25 Mar 2018 22:55:01 +0200 Subject: [PATCH 184/239] maint: Replace "build-aux/gnu-fetch" with 'fetch' maintainer rule Fetching third-party files inside a make rule is convenient and less error prone since 'make' has access to '$srcdir'. * build-aux/gnu-fetch: Delete. * maint.mk (WGET, git_sv_host, sv_git_am, sv_git_gl) (fetchfiles): New macros. (fetch): New target. * HACKING : Update instructions. --- HACKING | 2 +- build-aux/gnu-fetch | 97 --------------------------------------------- maint.mk | 43 ++++++++++++++++++++ 3 files changed, 44 insertions(+), 98 deletions(-) delete mode 100755 build-aux/gnu-fetch diff --git a/HACKING b/HACKING index e51515c..a2f0d13 100644 --- a/HACKING +++ b/HACKING @@ -55,7 +55,7 @@ follows. * Updating auxilary scripts Fetch new versions of the files that are maintained in other GNU - repositories by running "cd build-aux; ./gnu-fetch". In case any file in the + repositories by running "make fetch". In case any file in the Mcron repository has been updated, commit and re-run the testsuite. * Code coverage diff --git a/build-aux/gnu-fetch b/build-aux/gnu-fetch deleted file mode 100755 index 5655b16..0000000 --- a/build-aux/gnu-fetch +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/sh -# Fetch files maintained in other GNU repositories. - -scriptversion=2018-03-24.21; # UTC - -# Copyright © 2018 Mathieu Lirzin -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -set -e - -WGET=wget - -# Git repositories on Savannah. -git_sv_host='git.savannah.gnu.org' - -# Some repositories we sync files from. -sv_git_am="https://${git_sv_host}/gitweb/?p=automake.git;a=blob_plain;hb=HEAD;f=" -sv_git_gl="https://${git_sv_host}/gitweb/?p=gnulib.git;a=blob_plain;hb=HEAD;f=" - -# Files that we fetch and which we compare against. -# Note that the 'lib/COPYING' file must still be synced by hand. -FETCHFILES=" - ${sv_git_am}contrib/test-driver.scm - ${sv_git_gl}build-aux/gitlog-to-changelog - ${sv_git_gl}build-aux/do-release-commit-and-tag - ${sv_git_gl}build-aux/gnu-web-doc-update - ${sv_git_gl}build-aux/gnupload -" - -usage="Usage: $0 - -fetch files maintained in other GNU repositories -" - -while test -n "$1" -do - case $1 in - -*) - case $1 in - --help) - echo "$usage" - exit $? - ;; - --version) - echo "gnu-fetch $scriptversion" - exit $? - ;; - --) - shift - break - ;; - -*) - echo "$0: Unknown option '$1', try '$0 --help'" 1>&2 - exit 1 - ;; - esac - ;; - esac - shift -done - -rm -rf Fetchdir -mkdir Fetchdir -for url in ${FETCHFILES} -do - file=`printf '%s\n' "$url" | sed 's|^.*/||; s|^.*=||'` - "$WGET" -nv "$url" -O "Fetchdir/$file" || exit 1 - if cmp "Fetchdir/$file" "$file" >/dev/null; then - : Nothing to do - else - echo "$0: updating file $file" - cp "Fetchdir/$file" "$file" || exit 1 - fi -done -rm -rf Fetchdir - -exit 0 - -# Local variables: -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC0" -# time-stamp-end: "; # UTC" -# End: diff --git a/maint.mk b/maint.mk index 791e366..115fde6 100644 --- a/maint.mk +++ b/maint.mk @@ -18,3 +18,46 @@ # Rebuild Makefile.in if this file is modifed. Makefile.in: maint.mk + +## -------------------- ## +## Third-party files. ## +## ---------------------## + +WGET = wget + +# Git repositories on Savannah. +git_sv_host = git.savannah.gnu.org + +# Some repositories we sync files from. +sv_git_am = 'https://$(git_sv_host)/gitweb/?p=automake.git;a=blob_plain;hb=HEAD;f=' +sv_git_gl = 'https://$(git_sv_host)/gitweb/?p=gnulib.git;a=blob_plain;hb=HEAD;f=' + +# Files that we fetch and which we compare against. +# Note that the 'lib/COPYING' file must still be synced by hand. +fetchfiles = \ + $(sv_git_am)contrib/test-driver.scm \ + $(sv_git_gl)build-aux/do-release-commit-and-tag \ + $(sv_git_gl)build-aux/gitlog-to-changelog \ + ${sv_git_gl}build-aux/gnu-web-doc-update \ + $(sv_git_gl)build-aux/gnupload + +# Fetch the latest versions of few scripts and files we care about. +# A retrieval failure or a copying failure usually mean serious problems, +# so we'll just bail out if 'wget' or 'cp' fail. +fetch: + $(AM_V_at)rm -rf Fetchdir + $(AM_V_at)mkdir Fetchdir + $(AM_V_GEN)set -e; \ + if $(AM_V_P); then wget_opts=; else wget_opts=-nv; fi; \ + for url in $(fetchfiles); do \ + file=`printf '%s\n' "$$url" | sed 's|^.*/||; s|^.*=||'`; \ + $(WGET) $$wget_opts "$$url" -O Fetchdir/$$file || exit 1; \ + if cmp Fetchdir/$$file $(srcdir)/build-aux/$$file >/dev/null; then \ + : Nothing to do; \ + else \ + echo "$@: updating file $$file"; \ + cp Fetchdir/$$file $(srcdir)/build-aux/$$file || exit 1; \ + fi; \ + done + $(AM_V_at)rm -rf Fetchdir +.PHONY: fetch From fad58ca8c221def75093463e917f66fc006f3df5 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 26 Mar 2018 16:39:13 +0200 Subject: [PATCH 185/239] job-specifier: Preserve '%find-best-next' arguments exactness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The behavior of the 'min' procedure which converts its parameters to inexact numbers when at least one of them is inexact was causing '%find-best-next' to always return real numbers. * src/mcron/job-specifier.scm (%find-best-next): Preserve the exactness of numbers in NEXT-LIST. * tests/job-specifier.scm ("%find-best-next: exact"): New test. Reported-by: Ludovic Courtès --- src/mcron/job-specifier.scm | 8 ++++++-- tests/job-specifier.scm | 11 ++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/mcron/job-specifier.scm b/src/mcron/job-specifier.scm index 5c8e171..e3b3391 100644 --- a/src/mcron/job-specifier.scm +++ b/src/mcron/job-specifier.scm @@ -60,12 +60,16 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." ;; consisting of the smallest element of the NEXT-LIST, and the smallest ;; element larger than the CURRENT value. If an example of the latter ;; cannot be found, +INF.0 will be returned. + (define (exact-min a b) + ;; An implement of 'min' which preserves the exactness its arguments. + (if (< a b) a b)) + (let loop ((smallest (inf)) (closest+ (inf)) (lst next-list)) (match lst (() (cons smallest closest+)) ((time . rest) - (loop (min time smallest) - (if (> time current) (min time closest+) closest+) + (loop (exact-min time smallest) + (if (> time current) (exact-min time closest+) closest+) rest))))) (define (bump-time time value-list component higher-component diff --git a/tests/job-specifier.scm b/tests/job-specifier.scm index 889530b..48a46de 100644 --- a/tests/job-specifier.scm +++ b/tests/job-specifier.scm @@ -16,7 +16,8 @@ ;;; You should have received a copy of the GNU General Public License ;;; along with GNU Mcron. If not, see . -(use-modules (srfi srfi-64) +(use-modules (ice-9 match) + (srfi srfi-64) (mcron job-specifier)) (test-begin "job-specifier") @@ -40,4 +41,12 @@ (test-assert "range: reverse boundaries" (range 10 3)) +(define %find-best-next (@@ (mcron job-specifier) %find-best-next)) + +(test-assert "%find-best-next: exact" + ;; Ensure that '%find-best-next' preserves the exactness of the numbers + ;; inside the NEXT-LIST argument. + (match (pk 'match (%find-best-next 1 '(0 2))) + ((a . b) (and (exact? a) (exact? b))))) + (test-end) From f71b0b8310e6b297866147a11e3fd0dd5db13beb Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 26 Mar 2018 16:56:40 +0200 Subject: [PATCH 186/239] job-specifier: Adapt 'bump-time' to 'next-...-from' procedures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a follow-up to commit 913e3c65e4f56476e8ac69f4892cf92c125751ec. Since 'next-...-from' procedures now uses an '#:optional' argument instead of a dotted optional arguments list, 'bump-time' doesn't need to unwrap VALUE-LIST anymore. * src/mcron/job-specifier.scm (bump-time): Pass VALUE-LIST directly to '%find-best-next'. * tests/job-specifier.scm ("next-hour-from"): New test. * NEWS: Update. Reported-by: Ludovic Courtès --- NEWS | 6 ++++++ src/mcron/job-specifier.scm | 24 +++++++++--------------- tests/job-specifier.scm | 4 ++++ 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/NEWS b/NEWS index f27a92c..e76f4bb 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,12 @@ GNU Mcron NEWS -*- outline -*- The programs now sets the GUILE_LOAD_PATH and GUILE_LOAD_COMPILED_PATH environment variables with the location of the installed Guile modules. + 'next-year-from', 'next-year', 'next-month-from', 'next-month', + 'next-day-from', 'next-day', 'next-hour-from', 'next-hour', + 'next-minute-from', 'next-minute', 'next-second-from', and 'next-second' no + longer crashes when passing an optional arguments. + [bug introduced in mcron-1.1] + ** Improvements Some basic tests for the installed programs can be run after 'make install' diff --git a/src/mcron/job-specifier.scm b/src/mcron/job-specifier.scm index e3b3391..d3d3a2a 100644 --- a/src/mcron/job-specifier.scm +++ b/src/mcron/job-specifier.scm @@ -85,21 +85,15 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." ;; ;; ... except that the function is actually generalized to deal with ;; seconds, minutes, etc., in an obvious way :-) - ;; - ;; Note that value-list always comes from an optional argument to a - ;; procedure, so is wrapped up as the first element of a list (i.e. it is a - ;; list inside a list). - (match value-list - (() - (set-component! time (1+ (component time)))) - ((val . rest) - (match (%find-best-next (component time) val) - ((smallest . closest+) - (cond ((inf? closest+) - (set-higher-component! time (1+ (higher-component time))) - (set-component! time smallest)) - (else - (set-component! time closest+))))))) + (if (null? value-list) + (set-component! time (1+ (component time))) + (match (%find-best-next (component time) value-list) + ((smallest . closest+) + (cond ((inf? closest+) + (set-higher-component! time (1+ (higher-component time))) + (set-component! time smallest)) + (else + (set-component! time closest+)))))) (first (mktime time))) ;; Set of configuration methods which use the above general function to bump diff --git a/tests/job-specifier.scm b/tests/job-specifier.scm index 48a46de..dbf98f0 100644 --- a/tests/job-specifier.scm +++ b/tests/job-specifier.scm @@ -49,4 +49,8 @@ (match (pk 'match (%find-best-next 1 '(0 2))) ((a . b) (and (exact? a) (exact? b))))) +(test-equal "next-hour-from" + 7200 + (next-hour-from 10 '(0 3 7))) + (test-end) From 95fb9140257ec83bc7ac830fe9a10b802def131e Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 26 Mar 2018 20:27:12 +0200 Subject: [PATCH 187/239] base: Check how child processes are handled * tests/base.scm ("run-job: basic"): Check the number of children too. ("child-cleanup: one", "update-number-children!: set value"): New tests. --- tests/base.scm | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/tests/base.scm b/tests/base.scm index 39e35fd..eb9e11a 100644 --- a/tests/base.scm +++ b/tests/base.scm @@ -158,6 +158,7 @@ ;;; Import private procedures. (define update-number-children! (@@ (mcron base) update-number-children!)) +(define child-cleanup (@@ (mcron base) child-cleanup)) (define run-job (@@ (mcron base) run-job)) ;;; Check 'number-children' initial value. @@ -180,19 +181,35 @@ (update-number-children! 1-) (unbox number-children))) -;;; Check 'run-job' basic call. +;;; Check 'update-number-children!' constant value. +(test-equal "update-number-children!: set value" + 0 + (begin + (update-number-children! (const 0)) + (unbox number-children))) + +;;; Check 'run-job' and 'child-cleanup'. ;;; XXX: Having to use the filesystem for a unit test is wrong. (let* ((filename (tmpnam)) (action (λ () (close-port (open-output-file filename)))) (job (make-dummy-job #:user (getpw (getuid)) #:action action))) (dynamic-wind + (const #t) (λ () + (sigaction SIGCHLD (const #t)) (run-job job) - (waitpid WAIT_ANY)) + ;; Wait for the SIGCHLD signal sent when job exits. + (pause) + ;; Check 'run-job' result and if the number of children is up-to-date. + (test-equal "run-job: basic" + 1 + (and (access? filename F_OK) + (unbox number-children))) + (child-cleanup) + ;; Check that 'child-cleanup' updates the number of children. + (test-equal "child-cleanup: one" 0 (unbox number-children))) (λ () - (test-assert "run-job: basic" - (access? filename F_OK))) - (λ () - (delete-file filename)))) + (and (access? filename F_OK) (delete-file filename)) + (sigaction SIGCHLD SIG_DFL)))) (test-end) From c263834da9aa7c45050b015c11109e7f16653ea1 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 26 Mar 2018 21:59:58 +0200 Subject: [PATCH 188/239] job-specifier: Fix typo "implement" => "implementation" * src/mcron/job-specifier.scm (%find-best-next): Fix typo. --- src/mcron/job-specifier.scm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mcron/job-specifier.scm b/src/mcron/job-specifier.scm index d3d3a2a..cbfa2df 100644 --- a/src/mcron/job-specifier.scm +++ b/src/mcron/job-specifier.scm @@ -61,7 +61,8 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." ;; element larger than the CURRENT value. If an example of the latter ;; cannot be found, +INF.0 will be returned. (define (exact-min a b) - ;; An implement of 'min' which preserves the exactness its arguments. + ;; A binary implementation of 'min' which preserves the exactness of its + ;; arguments. (if (< a b) a b)) (let loop ((smallest (inf)) (closest+ (inf)) (lst next-list)) From 56f85cfd8aef4a0f2668c5fa72ae032ff1652c8b Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 26 Mar 2018 22:38:49 +0200 Subject: [PATCH 189/239] job-specifier: Check 'next-...' procedures * tests/job-specifier.scm ("next-year", "next-month", "next-day") ("next-hour", "next-minute", "next-second"): New tests. ("next-hour-from"): Remove. --- tests/job-specifier.scm | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/tests/job-specifier.scm b/tests/job-specifier.scm index dbf98f0..d0c6ae3 100644 --- a/tests/job-specifier.scm +++ b/tests/job-specifier.scm @@ -49,8 +49,41 @@ (match (pk 'match (%find-best-next 1 '(0 2))) ((a . b) (and (exact? a) (exact? b))))) -(test-equal "next-hour-from" - 7200 - (next-hour-from 10 '(0 3 7))) +;;; +;;; Check 'next-...' procedures. +;;; + +;;; TODO: Find more meaningful date examples. + +(test-equal "next-year" + (list 59989762800 1546293600) + (list (next-year '(1971)) + (next-year-from 1522095469))) + +(test-equal "next-month" + (list 28854000 5094000) + (list (next-month '(11)) + (next-month-from 101 '(0 2 4)))) + +(test-equal "next-day" + (list 2588400 342000) + (list (next-day '(31)) + (next-day-from 4337 '(0 5 10)))) + +(test-equal "next-hour" + '(3600 82800 3600) + (list (next-hour) + (next-hour '(0)) + (next-hour-from 3 '(0 1 2 3 4)))) + +(test-equal "next-minute" + '(240 60) + (list (next-minute '(4 9)) + (next-minute-from 8))) + +(test-equal "next-second" + '(52 15) + (list (next-second '(52 55)) + (next-second-from 14))) (test-end) From 15fa52f7ec85b3c2cb9f00ec8609dfe63a9ea9cd Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 26 Mar 2018 22:42:26 +0200 Subject: [PATCH 190/239] job-specifier: Box 'configuration-user' global variable * src/mcron/job-specifier.scm (configuration-user): Box it using SRFI-111 to be explicit about the mutability of this object. (job): Adapt. (set-configuration-user): Adapt and use 'get-user'. * tests/job-specifier.scm ("set-configuration-user: passwd entry") ("set-configuration-user: invalid uid", "set-configuration-user: uid") ("set-configuration-user: invalid spec") ("set-configuration-user: name"): New tests. --- src/mcron/job-specifier.scm | 10 ++++---- tests/job-specifier.scm | 46 +++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/mcron/job-specifier.scm b/src/mcron/job-specifier.scm index cbfa2df..120bf99 100644 --- a/src/mcron/job-specifier.scm +++ b/src/mcron/job-specifier.scm @@ -33,6 +33,7 @@ #:use-module (mcron utils) #:use-module (mcron vixie-time) #:use-module (srfi srfi-1) + #:use-module (srfi srfi-111) #:re-export (append-environment-mods) #:export (range next-year-from next-year @@ -186,17 +187,14 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." ;; time; a UID is stored with each job and it is that which takes effect when ;; the job actually runs. -(define configuration-user (getpw (getuid))) +(define configuration-user (box (getpw (getuid)))) (define configuration-time ;; Use SOURCE_DATE_EPOCH environment variable to support reproducible tests. (if (getenv "SOURCE_DATE_EPOCH") 0 (current-time))) (define (set-configuration-user user) - (set! configuration-user (if (or (string? user) - (integer? user)) - (getpw user) - user))) + (set-box! configuration-user (get-user user))) (define (set-configuration-time time) (set! configuration-time time)) @@ -218,7 +216,7 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." ;; right at the top of this program). (define* (job time-proc action #:optional displayable - #:key (user configuration-user)) + #:key (user (unbox configuration-user))) (let ((action (cond ((procedure? action) action) ((list? action) (lambda () (primitive-eval action))) ((string? action) (lambda () (system action))) diff --git a/tests/job-specifier.scm b/tests/job-specifier.scm index d0c6ae3..636c1a1 100644 --- a/tests/job-specifier.scm +++ b/tests/job-specifier.scm @@ -18,6 +18,7 @@ (use-modules (ice-9 match) (srfi srfi-64) + (srfi srfi-111) (mcron job-specifier)) (test-begin "job-specifier") @@ -86,4 +87,49 @@ (list (next-second '(52 55)) (next-second-from 14))) +;;; +;;; Check 'configuration-user' manipulation +;;; + +(define configuration-user (@@ (mcron job-specifier) configuration-user)) + +;;; Call 'set-configuration-user' with a valid uid. +(let ((uid (getuid))) + (test-equal "set-configuration-user: uid" + uid + (begin + (set-configuration-user uid) + (passwd:uid (unbox configuration-user))))) + +(define entry + ;; Random user entry. + (getpw)) + +;;; Call 'set-configuration-user' with a valid user name. +(let ((name (passwd:name entry))) + (test-equal "set-configuration-user: name" + name + (begin + (set-configuration-user name) + (passwd:name (unbox configuration-user))))) + +(define root-entry (getpw 0)) + +;;; Call 'set-configuration-user' with a passwd entry. +(test-equal "set-configuration-user: passwd entry" + root-entry + (begin + (set-configuration-user root-entry) + (unbox configuration-user))) + +;;; Call 'set-configuration-user' with an invalid uid. +(test-error "set-configuration-user: invalid uid" + #t + (set-configuration-user -20000)) + +;;; Call 'set-configuration-user' with an invalid spec. +(test-error "set-configuration-user: invalid spec" + #t + (set-configuration-user 'wrong)) + (test-end) From 8ab0465d92159cee9649210c9088641dd3ab4d6f Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 27 Mar 2018 00:23:37 +0200 Subject: [PATCH 191/239] job-specifier: Check 'job' * tests/job-specifier.scm ("job: procedure timeproc") ("job: list timeproc", "job: string timeproc", "job: list action") ("job: invalid string timeproc", "job: invalid timeproc") ("job: procedure action", "job: string action") ("job: user name"): New tests. --- tests/job-specifier.scm | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/job-specifier.scm b/tests/job-specifier.scm index 636c1a1..baf96af 100644 --- a/tests/job-specifier.scm +++ b/tests/job-specifier.scm @@ -132,4 +132,41 @@ #t (set-configuration-user 'wrong)) +;;; +;;; Check the 'job' procedure +;;; + +(test-assert "job: procedure timeproc" + (job 1+ "dummy action")) + +(test-assert "job: list timeproc" + (job '(next-hour '(0)) "dummy action")) + +(test-assert "job: string timeproc" + (job "30 4 1,15 * 5" "dummy action")) + +(test-error "job: invalid string timeproc" + 'mcron-error + (job "30 4 1,15 * WRONG" "dummy action")) + +(test-error "job: invalid timeproc" + 'mcron-error + (job 42 "dummy action")) + +(test-assert "job: procedure action" + (job 1+ (λ () (display "hello\n")))) + +(test-assert "job: list action" + (job 1+ '(display "hello\n"))) + +(test-assert "job: string action" + (job 1+ "echo hello")) + +(test-error "job: string action" + 'mcron-error + (job 1+ 42)) + +(test-assert "job: user name" + (job 1+ "dummy action" #:user (getuid))) + (test-end) From 729bae0c984021b6b0b18aecc76408bd52f9e6ad Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 27 Mar 2018 01:58:08 +0200 Subject: [PATCH 192/239] utils: Remove 'parse-args' It seems that it is not useful to catch 'misc-error exception when calling 'getopt-long'. Since 'parse-args' purpose was only to catch this particular error, it can be deleted. * src/mcron/utils.scm (parse-args): Remove. --- src/mcron/scripts/cron.scm | 3 ++- src/mcron/scripts/crontab.scm | 3 ++- src/mcron/utils.scm | 12 +----------- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/mcron/scripts/cron.scm b/src/mcron/scripts/cron.scm index 323499e..1a97fdf 100644 --- a/src/mcron/scripts/cron.scm +++ b/src/mcron/scripts/cron.scm @@ -18,6 +18,7 @@ ;;; along with GNU Mcron. If not, see . (define-module (mcron scripts cron) + #:use-module (ice-9 getopt-long) #:use-module (ice-9 ftw) #:use-module (mcron base) #:use-module (mcron config) @@ -134,7 +135,7 @@ option.\n") ;;; (define* (main #:optional (args (command-line))) - (let ((opts (parse-args args %options))) + (let ((opts (getopt-long args %options))) (when config-debug (debug-enable 'backtrace)) (cond diff --git a/src/mcron/scripts/crontab.scm b/src/mcron/scripts/crontab.scm index abc3d7b..902d3fc 100644 --- a/src/mcron/scripts/crontab.scm +++ b/src/mcron/scripts/crontab.scm @@ -18,6 +18,7 @@ ;;; along with GNU Mcron. If not, see . (define-module (mcron scripts crontab) + #:use-module (ice-9 getopt-long) #:use-module (ice-9 rdelim) #:use-module (mcron config) #:use-module (mcron utils) @@ -78,7 +79,7 @@ USER-NAME has modified his crontab. USER-NAME is written to the ;;; (define* (main #:optional (args (command-line))) - (let ((opts (parse-args args %options))) + (let ((opts (getopt-long args %options))) (when config-debug (debug-enable 'backtrace)) (cond ((option-ref opts 'help #f) diff --git a/src/mcron/utils.scm b/src/mcron/utils.scm index da72ea5..00cf0c5 100644 --- a/src/mcron/utils.scm +++ b/src/mcron/utils.scm @@ -18,7 +18,6 @@ ;;; along with GNU Mcron. If not, see . (define-module (mcron utils) - #:use-module (ice-9 getopt-long) #:use-module (ice-9 rdelim) #:use-module (mcron config) #:use-module (mcron base) @@ -26,13 +25,11 @@ #:use-module (mcron vixie-specification) #:export (catch-mcron-error mcron-error - parse-args show-version show-package-information process-update-request get-user) - #:re-export (option-ref - read-string)) + #:re-export (read-string)) (define (mcron-error exit-code . rest) "Print an error message (made up from the parts of REST), and if the @@ -53,13 +50,6 @@ and exit with its error code." (lambda (key exit-code . msg) (apply mcron-error exit-code msg)))) -(define (parse-args args option-desc-list) - "Parse ARGS with OPTION-DESC-LIST specification." - (catch 'misc-error - (lambda () (getopt-long args option-desc-list)) - (lambda (key func fmt args . rest) - (mcron-error 1 (apply format (append (list #f fmt) args)))))) - (define (show-version command) "Display version information for COMMAND and quit." (let* ((name config-package-name) From d8127a386c4474543c17d0641ed0fd2f1b21f97b Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Tue, 27 Mar 2018 02:03:40 +0200 Subject: [PATCH 193/239] utils: Check 'show-version' and 'show-package-information' * tests/utils.scm ("show-package-information") ("show-version"): New tests. --- tests/utils.scm | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/utils.scm b/tests/utils.scm index fbd32e1..0625850 100644 --- a/tests/utils.scm +++ b/tests/utils.scm @@ -19,6 +19,7 @@ (use-modules (ice-9 match) (ice-9 rdelim) (srfi srfi-64) + (mcron config) (mcron utils)) (test-begin "utils") @@ -63,6 +64,23 @@ (with-output-to-string (λ () (mcron-error 0 "foo" "bar")))) +;;; +;;; Check user interface conformance to GNU Coding Standards +;;; + +(test-assert "show-version" + (let ((out (with-output-to-string (λ () (show-version "dummy"))))) + (and (string-contains out config-package-version) + (string-contains out config-package-name)))) + +(test-assert "show-package-information" + (let ((out (with-output-to-string (λ () (show-package-information))))) + (string-contains out config-package-bugreport))) + +;;; +;;; Check 'get-user' +;;; + (define entry ;; Random user entry. (getpw)) From ef452ce43b80959ab25b4a8bd90942c2ea1a9122 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 1 Apr 2018 21:44:28 +0200 Subject: [PATCH 194/239] vixie-time: Adapt to '%find-best-next' possible infinite result This is a follow up to commit ae6deb8ea23570c02a7b575a53bba37048aab59f. * src/mcron/vixie-time.scm (increment-time-component): Check if '%find-best-next' returns '+inf.0' not 9999. --- src/mcron/vixie-time.scm | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/mcron/vixie-time.scm b/src/mcron/vixie-time.scm index c4d6bd9..0a39e41 100644 --- a/src/mcron/vixie-time.scm +++ b/src/mcron/vixie-time.scm @@ -1,5 +1,6 @@ ;;;; vixie-time.scm -- parse Vixie-style times ;;; Copyright © 2003 Dale Mellor +;;; Copyright © 2018 Mathieu Lirzin ;;; ;;; This file is part of GNU Mcron. ;;; @@ -17,6 +18,7 @@ ;;; along with GNU Mcron. If not, see . (define-module (mcron vixie-time) + #:use-module (ice-9 match) #:use-module (ice-9 regex) #:use-module (mcron job-specifier) #:use-module (srfi srfi-1) @@ -176,16 +178,17 @@ ;; simply unreadable without all of these aliases. (define (increment-time-component time time-spec) - (let* ((time-list (time-spec:list time-spec)) - (getter (time-spec:getter time-spec)) - (setter (time-spec:setter time-spec)) - (find-best-next (@@ (mcron job-specifier) %find-best-next)) - (next-best (find-best-next (getter time) time-list)) - (wrap-around (eqv? (cdr next-best) 9999))) - (setter time ((if wrap-around car cdr) next-best)) - wrap-around)) - - + (let ((time-list (time-spec:list time-spec)) + (getter (time-spec:getter time-spec)) + (setter (time-spec:setter time-spec)) + (find-best-next (@@ (mcron job-specifier) %find-best-next))) + (match (find-best-next (getter time) time-list) + ((smallest . closest+) + (let ((infinite (inf? closest+))) + (if infinite + (setter time smallest) + (setter time closest+)) + infinite))))) ;; There now follows a set of procedures for adjusting an element of time, ;; i.e. taking it to the next acceptable value. In each case, the head of the From 9187aeb78f2237e91ec0bc9b47a3ec46f8bf0382 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 8 Apr 2018 15:56:30 +0200 Subject: [PATCH 195/239] tests: Add "tests/vixie-time.scm" * tests/vixie-time.scm: New test. * Makefile.am (TESTS): Add it. --- Makefile.am | 3 +- tests/vixie-time.scm | 118 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 tests/vixie-time.scm diff --git a/Makefile.am b/Makefile.am index d551e5d..fdfbef3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -139,7 +139,8 @@ TESTS = \ tests/base.scm \ tests/environment.scm \ tests/job-specifier.scm \ - tests/utils.scm + tests/utils.scm \ + tests/vixie-time.scm ## -------------- ## ## Distribution. ## diff --git a/tests/vixie-time.scm b/tests/vixie-time.scm new file mode 100644 index 0000000..e5db67a --- /dev/null +++ b/tests/vixie-time.scm @@ -0,0 +1,118 @@ +;;;; vixie-time.scm -- tests for (mcron vixie-time) module +;;; Copyright © 2018 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . + +(use-modules (srfi srfi-1) + (srfi srfi-64) + (mcron vixie-time)) + +(setenv "TZ" "UTC0") + +(test-begin "vixie-time") + +(define (times-equal spec times proc) + (test-equal spec + (cdr times) + (fold-right (λ (val acc) + (cons (proc val) acc)) + '() + (drop-right times 1)))) + +(times-equal + "every minute" + '(0 60 120 180 240 300 360 420) + (parse-vixie-time "* * * * *")) + +(times-equal + "every hour" + (list 0 + 3600 + (* 2 3600) + (* 3 3600) + (* 4 3600) + (* 5 3600) + (* 6 3600) + (* 7 3600)) + (parse-vixie-time "0 * * * *")) + +(times-equal + "every day" + (list 0 + (* 24 3600) + (* 2 24 3600) + (* 3 24 3600) + (* 4 24 3600) + (* 5 24 3600) + (* 6 24 3600) + (* 7 24 3600)) + (parse-vixie-time "0 0 * * *")) + +(times-equal + "every month" + (list 0 + (* 31 86400) ;jan + (* (+ 31 28) 86400) ;fev + (* (+ 31 28 31) 86400) ;mar + (* (+ 31 28 31 30) 86400) ;avr + (* (+ 31 28 31 30 31) 86400) ;may + (* (+ 31 28 31 30 31 30) 86400) ;jun + (* (+ 31 28 31 30 31 30 31) 86400)) ;july + (parse-vixie-time "0 0 1 * *")) + +(times-equal + "every year" + (list 0 + (* 365 86400) ;1971 + (* 2 365 86400) ;1972 (leap) + (* (+ (* 2 365) 366) 86400) ;1973 + (* (+ (* 3 365) 366) 86400) ;1974 + (* (+ (* 4 365) 366) 86400) ;1975 + (* (+ (* 5 365) 366) 86400) ;1976 (leap) + (* (+ (* 5 365) (* 2 366)) 86400)) ;1977 + (parse-vixie-time "0 0 1 0 *")) + +(times-equal + "30 4 1,15 * 5" + (list 0 + (+ (* 4 3600) 1800) + (+ (* 28 3600) 1800) + (+ (* 8 86400) (* 4 3600) 1800) + (+ (* 13 86400) (* 28 3600) 1800) + (+ (* 15 86400) (* 4 3600) 1800) + (+ (* 532 3600) 1800)) + (parse-vixie-time "30 4 1,15 * 5")) + +;;; +;;; Errors +;;; + +;; FIXME: infinite loop +;; (test-error "month 0" #t +;; (let ((p (parse-vixie-time "0 0 0 * *"))) +;; (p 1234))) + +(test-error + "not enough fields" + 'mcron-error + (parse-vixie-time "1 2 3 4")) + +(test-error + "too many fields" + 'mcron-error + (parse-vixie-time "1 2 3 4 5 6")) + +(test-end) From 68be2dd2dda3fac06a3233b05e3336fa5e953f9d Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 8 Apr 2018 15:57:43 +0200 Subject: [PATCH 196/239] vixie-time: Refactor 'interpolate-weekdays' * src/mcron/vixie-time.scm (interpolate-weekdays): Avoid mutation and add 'range-wday' inner procedure. --- src/mcron/vixie-time.scm | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/mcron/vixie-time.scm b/src/mcron/vixie-time.scm index 0a39e41..64f0e87 100644 --- a/src/mcron/vixie-time.scm +++ b/src/mcron/vixie-time.scm @@ -122,27 +122,20 @@ (parse-vixie-subelement sub-element base limit)) (string-tokenize string (char-set-complement (char-set #\,)))))) - - -;; Consider there are two lists, one of days in the month, the other of days in -;; the week. This procedure returns an augmented list of days in the month with -;; weekdays accounted for. - (define (interpolate-weekdays mday-list wday-list month year) + "Given a list of days in the month MDAY-LIST and a list of days in the week +WDAY-LIST, return an augmented list of days in the month with weekdays +accounted for." (let ((t (localtime 0))) - (set-tm:mday t 1) - (set-tm:mon t month) - (set-tm:year t year) + (set-tm:mday t 1) + (set-tm:mon t month) + (set-tm:year t year) (let ((first-day (tm:wday (cdr (mktime t))))) - (apply append - mday-list - (map (lambda (wday) - (let ((first (- wday first-day))) - (if (< first 0) (set! first (+ first 7))) - (range (+ 1 first) 32 7))) - wday-list))))) - - + (define (range-wday wday) + (let* ((first (- wday first-day)) + (first* (if (negative? first) (+ 7 first) first))) + (range (1+ first*) 32 7))) + (apply append mday-list (map range-wday wday-list))))) ;; Return the number of days in a month. Fix up a tm object for the zero'th day ;; of the next month, rationalize the object and extract the day. From cf3146b3c5ae072d54e7ae29df06b060a549b8e8 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 8 Apr 2018 16:00:25 +0200 Subject: [PATCH 197/239] vixie-time: Refactor 'parse-vixie-time' * src/mcron/vixie-time.scm (parse-vixie-time): Use 'match' to avoid complex 'car' and 'cdr' usage. --- src/mcron/vixie-time.scm | 127 +++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 66 deletions(-) diff --git a/src/mcron/vixie-time.scm b/src/mcron/vixie-time.scm index 64f0e87..407ff60 100644 --- a/src/mcron/vixie-time.scm +++ b/src/mcron/vixie-time.scm @@ -307,73 +307,68 @@ accounted for." ((< (length tokens) 5) (throw 'mcron-error 9 "Not enough fields in Vixie-style time specification"))) - (let ((time-spec-list - (map-in-order (lambda (x) (vector - (let* ((n (vector-ref x 0)) - (tok (list-ref tokens n))) - (cond - ((and (= n 4) - (string=? tok "*") - (not (string=? - (list-ref tokens 2) "*"))) - '()) - ((and (= n 2) - (string=? tok "*") - (not (string=? - (list-ref tokens 4) "*"))) - '()) - (else - (parse-vixie-element - tok - (vector-ref x 1) - (vector-ref x 2))))) ; [0] - (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 ) - #( 2 1 32 ,tm:mday ,set-tm:mday ) - #( 3 0 12 ,tm:mon ,set-tm:mon ) - #( 4 0 7 ,tm:wday ,set-tm:wday ))))) ;; [1] + (match (map-in-order + (λ (x) + (vector + (let* ((n (vector-ref x 0)) + (tok (list-ref tokens n))) + (cond + ((and (= n 4) + (string=? tok "*") + (not (string=? + (list-ref tokens 2) "*"))) + '()) + ((and (= n 2) + (string=? tok "*") + (not (string=? + (list-ref tokens 4) "*"))) + '()) + (else + (parse-vixie-element + tok + (vector-ref x 1) + (vector-ref x 2))))) ; [0] + (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 ) + #( 2 1 32 ,tm:mday ,set-tm:mday ) + #( 3 0 12 ,tm:mon ,set-tm:mon ) + #( 4 0 7 ,tm:wday ,set-tm:wday ))) ;; [1] + ((and time-spec-list (min hour day month wday)) + (vector-set! wday + 0 + (map (lambda (time-spec) + (if (eqv? time-spec 7) 0 time-spec)) + (vector-ref wday 0))) ;; [2] - (vector-set! (car (last-pair time-spec-list)) - 0 - (map (lambda (time-spec) - (if (eqv? time-spec 7) 0 time-spec)) - (vector-ref (car (last-pair time-spec-list)) 0))) ;; [2] + (vector-set! day + 0 + (remove (lambda (d) (eqv? d 0)) + (vector-ref day 0))) ;; [2.1] - (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] - - (if (not (member (tm:mon time) - (time-spec:list (cadddr time-spec-list)))) - (begin - (nudge-month! time (cdddr 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))) - (if (not (member (tm:hour time) - (time-spec:list (cadr time-spec-list)))) - (begin - (nudge-hour! time (cdr time-spec-list)) - (set-tm:min time -1))) ;; [5] - - (set-tm:sec time 0) - (nudge-min! time time-spec-list) ;; [6] - (car (mktime time))))))) ;; [7] + (λ (current-time) ;; [3] + (let ((time (localtime current-time))) ;; [4] + (unless (member (tm:mon time) (time-spec:list month)) + (nudge-month! time (cdddr time-spec-list)) + (set-tm:mday time 0)) + (when (or (eqv? (tm:mday time) 0) + (not (member (tm:mday time) + (interpolate-weekdays + (time-spec:list day) + (time-spec:list wday) + (tm:mon time) + (tm:year time))))) + (nudge-day! (pk time) (pk (cddr time-spec-list))) + (set-tm:hour time -1)) + (unless (member (tm:hour time) + (time-spec:list hour)) + (nudge-hour! time (cdr time-spec-list)) + (set-tm:min time -1)) ;; [5] + + (set-tm:sec time 0) + (nudge-min! time time-spec-list) ;; [6] + (first (mktime time)))))))) ;; [7] From 4c32ff4944cdd361c2fe9be6b23a8ac8233123a1 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 8 Apr 2018 16:15:25 +0200 Subject: [PATCH 198/239] maint: Update NEWS * NEWS: Update. --- NEWS | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index e76f4bb..5b35d5b 100644 --- a/NEWS +++ b/NEWS @@ -13,7 +13,7 @@ GNU Mcron NEWS -*- outline -*- 'next-year-from', 'next-year', 'next-month-from', 'next-month', 'next-day-from', 'next-day', 'next-hour-from', 'next-hour', 'next-minute-from', 'next-minute', 'next-second-from', and 'next-second' no - longer crashes when passing an optional arguments. + longer crashes when passing an optional argument. [bug introduced in mcron-1.1] ** Improvements @@ -23,6 +23,9 @@ GNU Mcron NEWS -*- outline -*- The configuration files are now processed using a deterministic order. + The test suite code coverage for mcron modules is now at 66.8% in term of + number of lines (mcron-1.1 was at 23.7%). + * Noteworthy changes in release 1.1 (2018-03-19) [stable] ** New features From c2b3e6f12495e44f604dc5ce2675a2e4cce8d1aa Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 8 Apr 2018 16:43:39 +0200 Subject: [PATCH 199/239] maint: Update README * README: Do not include the version number. Refer to "HACKING" when "INSTALL" is not available. Tell about the "--disable-multi-user" configure option. --- README | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/README b/README index 542c5d3..7fe59f0 100644 --- a/README +++ b/README @@ -1,18 +1,11 @@ -GNU mcron --- README -*-text-*- - - Copyright (C) 2003, 2005, 2006, 2012, 2014 Dale Mellor - - Copying and distribution of this file, with or without modification, - are permitted in any medium without royalty provided the copyright - notice and this notice are preserved. - - -This is version 1.0.8 of the GNU mcron program. It is designed and written by -Dale Mellor, and 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...). +This is GNU Mcron, a tool to run jobs at scheduled times. It is a complete +replacement for Vixie cron. Besides supporting the traditional Vixie syntax +for its configuration files, GNU Mcron offers the possibility to define jobs +using the Scheme language. +See the INSTALL file for generic information about how to configure and +install GNU Mcron. If this file is not present, see HACKING for +preliminary build instructions. ---------------------------------------------------------------------- IMPORTANT NOTICES @@ -20,8 +13,8 @@ IMPORTANT NOTICES Do not (yet) install this software on a machine which relies for its functioning on its current set of crontabs. -For use as a replacement cron daemon on a system, the package must be installed -by root. +To not replace the cron daemon on a system, the package must be installed +with the --disable-multi-user configure option. 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 @@ -50,8 +43,6 @@ m.mcron, m.cron (or m.crond) and m.crontab. ---------------------------------------------------------------------- -See the file INSTALL for generic building and installation instructions. - After compilation, read the info file for full instructions for use (typing 'info -f doc/mcron.info' at the command line should suffice). Notes for end users, sysadmins, and developers who wish to incorporate mcron into their own @@ -66,3 +57,13 @@ Mcron is free software. See the file COPYING for copying conditions. The mcron development home page is at http://www.gnu.org/software/mcron, and it can be obtained from ftp://ftp.gnu.org/pub/gnu/mcron. + +----- + +Copyright © 2003, 2005, 2006, 2012, 2014 Dale Mellor +Copyright © 2018 Mathieu Lirzin + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. From a2d93e3b759be83722e130215a6db610cf155274 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 8 Apr 2018 16:54:49 +0200 Subject: [PATCH 200/239] maint: Update "maint.mk" * maint.mk (gpg_key_ID, gnu_rel_host, noteworthy_changes) (gnu_ftp_host-alpha, gnu_ftp_host-beta) (gnu_ftp_host-stable): New macros. (release, upload, web-manual, web-manual-update): New rules. --- maint.mk | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/maint.mk b/maint.mk index 115fde6..e45ede1 100644 --- a/maint.mk +++ b/maint.mk @@ -61,3 +61,66 @@ fetch: done $(AM_V_at)rm -rf Fetchdir .PHONY: fetch + +# If it's not already specified, derive the GPG key ID from +# the signed tag we've just applied to mark this release. +gpg_key_ID = \ + $$(cd $(srcdir) \ + && git cat-file tag v$(VERSION) \ + | gpgv --status-fd 1 --keyring /dev/null - - 2>/dev/null \ + | awk '/^\[GNUPG:\] ERRSIG / {print $$3; exit}') + +# Use alpha.gnu.org for alpha and beta releases. +# Use ftp.gnu.org for stable releases. +gnu_ftp_host-alpha = alpha.gnu.org +gnu_ftp_host-beta = alpha.gnu.org +gnu_ftp_host-stable = ftp.gnu.org +gnu_rel_host = $(gnu_ftp_host-$(release-type)) + +noteworthy_changes = * Noteworthy changes in release ?.? (????-??-??) [?] + +.PHONY: release +release: + cd $(srcdir) && rm -rf autom4te.cache && ./bootstrap && ./configure + $(AM_V_at)$(MAKE) Makefile + $(AM_V_at)$(srcdir)/build-aux/announce-gen \ + --mail-headers='To: ??? Mail-Followup-To: $(PACKAGE_BUGREPORT)' \ + --release-type=$(release-type) \ + --package=$(PACKAGE) \ + --prev=`cat .prev-version` \ + --curr=$(VERSION) \ + --gpg-key-id=$(gpg_key_ID) \ + --srcdir=$(srcdir) \ + --news=$(srcdir)/NEWS \ + --bootstrap-tools=autoconf,automake,help2man \ + --no-print-checksums \ + --url-dir=https://ftp.gnu.org/gnu/$(PACKAGE) \ + > ~/announce-$(PACKAGE)-$(VERSION) + $(AM_V_at)echo $(VERSION) > .prev-version + $(AM_V_at)perl -pi \ + -e '$$. == 3 and print "$(noteworthy_changes)\n\n\n"' \ + $(srcdir)/NEWS + $(AM_V_at)msg=`printf '%s\n' 'maint: Post-release administrivia' '' \ + '* NEWS: Add header line for next release.' \ + '* .prev-version: Record previous version.'` || exit 1; \ + git commit -m "$$msg" -a + +.PHONY: upload +upload: + $(srcdir)/build-aux/gnupload $(GNUPLOADFLAGS) \ + --to $(gnu_rel_host):$(PACKAGE) \ + $(DIST_ARCHIVES) + +.PHONY: web-manual +web-manual: + $(AM_V_at)cd '$(srcdir)/doc'; \ + $(SHELL) ../build-aux/gendocs.sh \ + -o '$(abs_builddir)/doc/manual' \ + --email $(PACKAGE_BUGREPORT) $(PACKAGE) \ + "$(PACKAGE_STRING) Reference Manual" + $(AM_V_at)echo " *** Upload the doc/manual directory to web-cvs." + +.PHONY: web-manual-update +web-manual-update: + $(AM_V_GEN)cd $(srcdir) \ + && build-aux/gnu-web-doc-update -C $(abs_builddir) From 1c5ec4594374ba09fe9fc1334d11f5ab50865750 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 8 Apr 2018 16:58:40 +0200 Subject: [PATCH 201/239] version 1.1.1 * NEWS: Record release date. --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 5b35d5b..893f0c5 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ GNU Mcron NEWS -*- outline -*- -* Noteworthy changes in release ?.? (????-??-??) [?] +* Noteworthy changes in release 1.1.1 (2018-04-08) [stable] ** Bug fixes From efa2f51ae329c07c54dd9d90615c96fb4045f4c8 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 8 Apr 2018 17:02:27 +0200 Subject: [PATCH 202/239] maint: Post-release administrivia * NEWS: Add header line for next release. * .prev-version: Record previous version. --- .prev-version | 2 +- NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.prev-version b/.prev-version index 9459d4b..524cb55 100644 --- a/.prev-version +++ b/.prev-version @@ -1 +1 @@ -1.1 +1.1.1 diff --git a/NEWS b/NEWS index 893f0c5..d3f31cd 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,8 @@ GNU Mcron NEWS -*- outline -*- +* Noteworthy changes in release ?.? (????-??-??) [?] + + * Noteworthy changes in release 1.1.1 (2018-04-08) [stable] ** Bug fixes From 7228d3048a89facee77689e390d5f5c091c57d73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E6=96=87=E6=AD=A6?= Date: Mon, 1 Oct 2018 14:07:48 +0800 Subject: [PATCH 203/239] build: Add '--with-sendmail' configure option This allows users to configure the Mail Transfert Agent (MTA) of their choice. * configure.ac: Add '--with-sendmail' option. (SENDMAIL): Default to 'sendmail -t'. * NEWS: Announce it. * src/mcron/redirect.scm (with-mail-out): Assume the MTA is reading the message for recipients. * build-aux/guix.scm: Remove 'which' from the native-inputs. --- NEWS | 6 ++++++ build-aux/guix.scm | 4 ++-- configure.ac | 30 ++++++++++-------------------- src/mcron/redirect.scm | 8 ++++---- 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/NEWS b/NEWS index d3f31cd..432e586 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,11 @@ GNU Mcron NEWS -*- outline -*- * Noteworthy changes in release ?.? (????-??-??) [?] +** Improvements + + The "--with-sendmail" configure variable has been added to allow the usage + of a different Mail Transfert Agent (MTA) than 'sendmail -t'. The MTA must + be able to guess the actual recipients from the 'To:' message header. * Noteworthy changes in release 1.1.1 (2018-04-08) [stable] @@ -157,6 +162,7 @@ GNU Mcron NEWS -*- outline -*- Copyright © 2003, 2005, 2006 Dale Mellor Copyright © 2017, 2018 Mathieu Lirzin +Copyright © 2018 宋文武 Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright diff --git a/build-aux/guix.scm b/build-aux/guix.scm index d90e0be..24927ad 100644 --- a/build-aux/guix.scm +++ b/build-aux/guix.scm @@ -1,5 +1,6 @@ ;;;; guix.scm -- Guix package definition ;;; Copyright © 2016 Mathieu Lirzin +;;; Copyright © 2018 宋文武 ;;; ;;; This file is part of GNU Mcron. ;;; @@ -62,5 +63,4 @@ ("automake" ,(specification->package "automake")) ("help2man" ,(specification->package "help2man")) ("pkg-config" ,(specification->package "pkg-config")) - ("texinfo" ,(specification->package "texinfo")) - ("which" ,(specification->package "which"))))) + ("texinfo" ,(specification->package "texinfo"))))) diff --git a/configure.ac b/configure.ac index 0bb9262..f7e3c34 100644 --- a/configure.ac +++ b/configure.ac @@ -2,6 +2,7 @@ # Copyright © 2003, 2005, 2012, 2014 Dale Mellor # # Copyright © 2015, 2016, 2017, 2018 Mathieu Lirzin +# Copyright © 2018 宋文武 # # This file is part of GNU Mcron. # @@ -55,26 +56,15 @@ GUILE_PROGS AM_MISSING_PROG(HELP2MAN, help2man, $missing_dir) -# Now find a sendmail or equivalent. - -AC_CHECK_PROGS(SENDMAIL, sendmail) -if test "x$ac_cv_prog_SENDMAIL" != "x"; then - AC_MSG_CHECKING(sendmail path and arguments) - ac_cv_prog_SENDMAIL="`$ac_cv_prog_WHICH sendmail` -FCronDaemon -odi -oem " -dnl -or0s" - AC_MSG_RESULT($ac_cv_prog_SENDMAIL) - -else - AC_CHECK_PROGS(SENDMAIL, mail) - if test "x$ac_cv_prog_SENDMAIL" != "x"; then - AC_MSG_CHECKING(mail path) - ac_cv_prog_SENDMAIL="`$ac_cv_prog_WHICH mail` -d " - AC_MSG_RESULT($ac_cv_prog_SENDMAIL) - else - AC_MSG_RESULT(No mail program found) - fi -fi -SENDMAIL=$ac_cv_prog_SENDMAIL +# Let users choose the Mail Transfert Agent (MTA) of their choice. Default to +# a non-absolute program name to make it a loose dependency resolved at +# runtime. +AC_ARG_WITH([sendmail], + [AS_HELP_STRING([--with-sendmail=COMMAND], + [command to read an email message from standard input, and send it])], + [SENDMAIL="$withval"], + [SENDMAIL="sendmail -t"]) +AC_SUBST([SENDMAIL]) AC_ARG_ENABLE([multi-user], [AS_HELP_STRING([--disable-multi-user], diff --git a/src/mcron/redirect.scm b/src/mcron/redirect.scm index 6711407..b7df42c 100644 --- a/src/mcron/redirect.scm +++ b/src/mcron/redirect.scm @@ -1,5 +1,6 @@ ;;;; redirect.scm -- modify job outputs ;;; Copyright © 2003 Dale Mellor +;;; Copyright © 2018 宋文武 ;;; ;;; This file is part of GNU Mcron. ;;; @@ -170,10 +171,9 @@ (set-current-output-port (if (and (string? mailto) (string=? mailto "")) (open-output-file "/dev/null") - (open-output-pipe - (string-append config-sendmail - " " - user)))) + ;; The sendmail command should read + ;; recipients from the message header. + (open-output-pipe config-sendmail))) (set-current-input-port (car child->parent)) (display "To: ") (display user) (newline) (display "From: mcron") (newline) From 0d045af94e8c7c14e47aa227b2e1f0da160ba5e0 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 7 Oct 2018 12:20:17 +0200 Subject: [PATCH 204/239] =?UTF-8?q?maint:=20Add=20=E5=AE=8B=E6=96=87?= =?UTF-8?q?=E6=AD=A6=20to=20the=20authors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * AUTHORS: Add 宋文武. --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index fe01d34..0668837 100644 --- a/AUTHORS +++ b/AUTHORS @@ -2,3 +2,4 @@ Dale Mellor Mathieu Lirzin Sergey Poznyakoff Ludovic Courtès +宋文武 From d51685b2eb31d72450cf8856827044d38b84dd07 Mon Sep 17 00:00:00 2001 From: Adam Bilbrough Date: Mon, 26 Nov 2018 05:24:42 +0100 Subject: [PATCH 205/239] version 1.1.2 * NEWS: Record release date. --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 432e586..359f819 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ GNU Mcron NEWS -*- outline -*- -* Noteworthy changes in release ?.? (????-??-??) [?] +* Noteworthy changes in release 1.1.2 (2018-11-26) [stable] ** Improvements From d4b48ee300dd1ea7c63666d8551c83a80b94b507 Mon Sep 17 00:00:00 2001 From: Adam Bilbrough Date: Mon, 26 Nov 2018 19:08:16 +0100 Subject: [PATCH 206/239] final push for 1.1.2 --- Makefile.am | 18 - build-aux/announce-gen | 0 build-aux/do-release-commit-and-tag | 0 build-aux/git-version-gen | 226 ------------- build-aux/gitlog-to-changelog | 499 ---------------------------- build-aux/gnu-web-doc-update | 0 build-aux/gnupload | 0 build-aux/guix.scm | 10 +- configure.ac | 5 +- maint.mk | 1 - 10 files changed, 2 insertions(+), 757 deletions(-) mode change 100644 => 100755 Makefile.am mode change 100755 => 100644 build-aux/announce-gen mode change 100755 => 100644 build-aux/do-release-commit-and-tag delete mode 100755 build-aux/git-version-gen delete mode 100755 build-aux/gitlog-to-changelog mode change 100755 => 100644 build-aux/gnu-web-doc-update mode change 100755 => 100644 build-aux/gnupload mode change 100644 => 100755 configure.ac mode change 100644 => 100755 maint.mk diff --git a/Makefile.am b/Makefile.am old mode 100644 new mode 100755 index fdfbef3..38b0a7b --- a/Makefile.am +++ b/Makefile.am @@ -146,24 +146,6 @@ TESTS = \ ## Distribution. ## ## -------------- ## -dist-hook: gen-ChangeLog - $(AM_V_GEN)echo $(VERSION) > $(distdir)/.tarball-version - -# Generate the ChangeLog file from Git commit logs. -gen_start_date = 2015-06-26 -.PHONY: gen-ChangeLog -gen-ChangeLog: - $(AM_V_GEN)if test -d $(srcdir)/.git; then \ - log_fix="$(srcdir)/build-aux/git-log-fix"; \ - test -e "$$log_fix" \ - && amend_git_log="--amend=$$log_fix" \ - || amend_git_log=; \ - $(top_srcdir)/build-aux/gitlog-to-changelog \ - $$amend_git_log --since=$(gen_start_date) > $(distdir)/cl-t && \ - { rm -f $(distdir)/ChangeLog && \ - mv $(distdir)/cl-t $(distdir)/ChangeLog; } \ - fi - EXTRA_DIST = \ bootstrap \ build-aux/guix.scm \ diff --git a/build-aux/announce-gen b/build-aux/announce-gen old mode 100755 new mode 100644 diff --git a/build-aux/do-release-commit-and-tag b/build-aux/do-release-commit-and-tag old mode 100755 new mode 100644 diff --git a/build-aux/git-version-gen b/build-aux/git-version-gen deleted file mode 100755 index bd2c4b6..0000000 --- a/build-aux/git-version-gen +++ /dev/null @@ -1,226 +0,0 @@ -#!/bin/sh -# Print a version string. -scriptversion=2016-05-08.18; # UTC - -# Copyright (C) 2007-2016 Free Software Foundation, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/. -# It may be run two ways: -# - from a git repository in which the "git describe" command below -# produces useful output (thus requiring at least one signed tag) -# - from a non-git-repo directory containing a .tarball-version file, which -# presumes this script is invoked like "./git-version-gen .tarball-version". - -# In order to use intra-version strings in your project, you will need two -# separate generated version string files: -# -# .tarball-version - present only in a distribution tarball, and not in -# a checked-out repository. Created with contents that were learned at -# the last time autoconf was run, and used by git-version-gen. Must not -# be present in either $(srcdir) or $(builddir) for git-version-gen to -# give accurate answers during normal development with a checked out tree, -# but must be present in a tarball when there is no version control system. -# Therefore, it cannot be used in any dependencies. GNUmakefile has -# hooks to force a reconfigure at distribution time to get the value -# correct, without penalizing normal development with extra reconfigures. -# -# .version - present in a checked-out repository and in a distribution -# tarball. Usable in dependencies, particularly for files that don't -# want to depend on config.h but do want to track version changes. -# Delete this file prior to any autoconf run where you want to rebuild -# files to pick up a version string change; and leave it stale to -# minimize rebuild time after unrelated changes to configure sources. -# -# As with any generated file in a VC'd directory, you should add -# /.version to .gitignore, so that you don't accidentally commit it. -# .tarball-version is never generated in a VC'd directory, so needn't -# be listed there. -# -# Use the following line in your configure.ac, so that $(VERSION) will -# automatically be up-to-date each time configure is run (and note that -# since configure.ac no longer includes a version string, Makefile rules -# should not depend on configure.ac for version updates). -# -# AC_INIT([GNU project], -# m4_esyscmd([build-aux/git-version-gen .tarball-version]), -# [bug-project@example]) -# -# Then use the following lines in your Makefile.am, so that .version -# will be present for dependencies, and so that .version and -# .tarball-version will exist in distribution tarballs. -# -# EXTRA_DIST = $(top_srcdir)/.version -# BUILT_SOURCES = $(top_srcdir)/.version -# $(top_srcdir)/.version: -# echo $(VERSION) > $@-t && mv $@-t $@ -# dist-hook: -# echo $(VERSION) > $(distdir)/.tarball-version - - -me=$0 - -version="git-version-gen $scriptversion - -Copyright 2011 Free Software Foundation, Inc. -There is NO warranty. You may redistribute this software -under the terms of the GNU General Public License. -For more information about these matters, see the files named COPYING." - -usage="\ -Usage: $me [OPTION]... \$srcdir/.tarball-version [TAG-NORMALIZATION-SED-SCRIPT] -Print a version string. - -Options: - - --prefix PREFIX prefix of git tags (default 'v') - --fallback VERSION - fallback version to use if \"git --version\" fails - - --help display this help and exit - --version output version information and exit - -Running without arguments will suffice in most cases." - -prefix=v -fallback= - -while test $# -gt 0; do - case $1 in - --help) echo "$usage"; exit 0;; - --version) echo "$version"; exit 0;; - --prefix) shift; prefix=${1?};; - --fallback) shift; fallback=${1?};; - -*) - echo "$0: Unknown option '$1'." >&2 - echo "$0: Try '--help' for more information." >&2 - exit 1;; - *) - if test "x$tarball_version_file" = x; then - tarball_version_file="$1" - elif test "x$tag_sed_script" = x; then - tag_sed_script="$1" - else - echo "$0: extra non-option argument '$1'." >&2 - exit 1 - fi;; - esac - shift -done - -if test "x$tarball_version_file" = x; then - echo "$usage" - exit 1 -fi - -tag_sed_script="${tag_sed_script:-s/x/x/}" - -nl=' -' - -# Avoid meddling by environment variable of the same name. -v= -v_from_git= - -# First see if there is a tarball-only version file. -# then try "git describe", then default. -if test -f $tarball_version_file -then - v=`cat $tarball_version_file` || v= - case $v in - *$nl*) v= ;; # reject multi-line output - [0-9]*) ;; - *) v= ;; - esac - test "x$v" = x \ - && echo "$0: WARNING: $tarball_version_file is missing or damaged" 1>&2 -fi - -if test "x$v" != x -then - : # use $v -# Otherwise, if there is at least one git commit involving the working -# directory, and "git describe" output looks sensible, use that to -# derive a version string. -elif test "`git log -1 --pretty=format:x . 2>&1`" = x \ - && v=`git describe --abbrev=4 --match="$prefix*" HEAD 2>/dev/null \ - || git describe --abbrev=4 HEAD 2>/dev/null` \ - && v=`printf '%s\n' "$v" | sed "$tag_sed_script"` \ - && case $v in - $prefix[0-9]*) ;; - *) (exit 1) ;; - esac -then - # Is this a new git that lists number of commits since the last - # tag or the previous older version that did not? - # Newer: v6.10-77-g0f8faeb - # Older: v6.10-g0f8faeb - case $v in - *-*-*) : git describe is okay three part flavor ;; - *-*) - : git describe is older two part flavor - # Recreate the number of commits and rewrite such that the - # result is the same as if we were using the newer version - # of git describe. - vtag=`echo "$v" | sed 's/-.*//'` - commit_list=`git rev-list "$vtag"..HEAD 2>/dev/null` \ - || { commit_list=failed; - echo "$0: WARNING: git rev-list failed" 1>&2; } - numcommits=`echo "$commit_list" | wc -l` - v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`; - test "$commit_list" = failed && v=UNKNOWN - ;; - esac - - # Change the first '-' to a '.', so version-comparing tools work properly. - # Remove the "g" in git describe's output string, to save a byte. - v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`; - v_from_git=1 -elif test "x$fallback" = x || git --version >/dev/null 2>&1; then - v=UNKNOWN -else - v=$fallback -fi - -v=`echo "$v" |sed "s/^$prefix//"` - -# Test whether to append the "-dirty" suffix only if the version -# string we're using came from git. I.e., skip the test if it's "UNKNOWN" -# or if it came from .tarball-version. -if test "x$v_from_git" != x; then - # Don't declare a version "dirty" merely because a time stamp has changed. - git update-index --refresh > /dev/null 2>&1 - - dirty=`exec 2>/dev/null;git diff-index --name-only HEAD` || dirty= - case "$dirty" in - '') ;; - *) # Append the suffix only if there isn't one already. - case $v in - *-dirty) ;; - *) v="$v-dirty" ;; - esac ;; - esac -fi - -# Omit the trailing newline, so that m4_esyscmd can use the result directly. -printf %s "$v" - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC0" -# time-stamp-end: "; # UTC" -# End: diff --git a/build-aux/gitlog-to-changelog b/build-aux/gitlog-to-changelog deleted file mode 100755 index 1e73f42..0000000 --- a/build-aux/gitlog-to-changelog +++ /dev/null @@ -1,499 +0,0 @@ -eval '(exit $?0)' && eval 'exec perl -wS "$0" "$@"' - & eval 'exec perl -wS "$0" $argv:q' - if 0; -# Convert git log output to ChangeLog format. - -my $VERSION = '2018-03-07 03:47'; # UTC -# The definition above must lie within the first 8 lines in order -# for the Emacs time-stamp write hook (at end) to update it. -# If you change this file with Emacs, please let the write hook -# do its job. Otherwise, update this string manually. - -# Copyright (C) 2008-2018 Free Software Foundation, Inc. - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# Written by Jim Meyering - -use strict; -use warnings; -use Getopt::Long; -use POSIX qw(strftime); - -(my $ME = $0) =~ s|.*/||; - -# use File::Coda; # https://meyering.net/code/Coda/ -END { - defined fileno STDOUT or return; - close STDOUT and return; - warn "$ME: failed to close standard output: $!\n"; - $? ||= 1; -} - -sub usage ($) -{ - my ($exit_code) = @_; - my $STREAM = ($exit_code == 0 ? *STDOUT : *STDERR); - if ($exit_code != 0) - { - print $STREAM "Try '$ME --help' for more information.\n"; - } - else - { - print $STREAM < ChangeLog - $ME -- -n 5 foo > last-5-commits-to-branch-foo - -SPECIAL SYNTAX: - -The following types of strings are interpreted specially when they appear -at the beginning of a log message line. They are not copied to the output. - - Copyright-paperwork-exempt: Yes - Append the "(tiny change)" notation to the usual "date name email" - ChangeLog header to mark a change that does not require a copyright - assignment. - Co-authored-by: Joe User - List the specified name and email address on a second - ChangeLog header, denoting a co-author. - Signed-off-by: Joe User - These lines are simply elided. - -In a FILE specified via --amend, comment lines (starting with "#") are ignored. -FILE must consist of pairs where SHA is a 40-byte SHA1 (alone on -a line) referring to a commit in the current project, and CODE refers to one -or more consecutive lines of Perl code. Pairs must be separated by one or -more blank line. - -Here is sample input for use with --amend=FILE, from coreutils: - -3a169f4c5d9159283548178668d2fae6fced3030 -# fix typo in title: -s/all tile types/all file types/ - -1379ed974f1fa39b12e2ffab18b3f7a607082202 -# Due to a bug in vc-dwim, I mis-attributed a patch by Paul to myself. -# Change the author to be Paul. Note the escaped "@": -s,Jim .*>,Paul Eggert , - -EOF - } - exit $exit_code; -} - -# If the string $S is a well-behaved file name, simply return it. -# If it contains white space, quotes, etc., quote it, and return the new string. -sub shell_quote($) -{ - my ($s) = @_; - if ($s =~ m![^\w+/.,-]!) - { - # Convert each single quote to '\'' - $s =~ s/\'/\'\\\'\'/g; - # Then single quote the string. - $s = "'$s'"; - } - return $s; -} - -sub quoted_cmd(@) -{ - return join (' ', map {shell_quote $_} @_); -} - -# Parse file F. -# Comment lines (starting with "#") are ignored. -# F must consist of pairs where SHA is a 40-byte SHA1 -# (alone on a line) referring to a commit in the current project, and -# CODE refers to one or more consecutive lines of Perl code. -# Pairs must be separated by one or more blank line. -sub parse_amend_file($) -{ - my ($f) = @_; - - open F, '<', $f - or die "$ME: $f: failed to open for reading: $!\n"; - - my $fail; - my $h = {}; - my $in_code = 0; - my $sha; - while (defined (my $line = )) - { - $line =~ /^\#/ - and next; - chomp $line; - $line eq '' - and $in_code = 0, next; - - if (!$in_code) - { - $line =~ /^([0-9a-fA-F]{40})$/ - or (warn "$ME: $f:$.: invalid line; expected an SHA1\n"), - $fail = 1, next; - $sha = lc $1; - $in_code = 1; - exists $h->{$sha} - and (warn "$ME: $f:$.: duplicate SHA1\n"), - $fail = 1, next; - } - else - { - $h->{$sha} ||= ''; - $h->{$sha} .= "$line\n"; - } - } - close F; - - $fail - and exit 1; - - return $h; -} - -# git_dir_option $SRCDIR -# -# From $SRCDIR, the --git-dir option to pass to git (none if $SRCDIR -# is undef). Return as a list (0 or 1 element). -sub git_dir_option($) -{ - my ($srcdir) = @_; - my @res = (); - if (defined $srcdir) - { - my $qdir = shell_quote $srcdir; - my $cmd = "cd $qdir && git rev-parse --show-toplevel"; - my $qcmd = shell_quote $cmd; - my $git_dir = qx($cmd); - defined $git_dir - or die "$ME: cannot run $qcmd: $!\n"; - $? == 0 - or die "$ME: $qcmd had unexpected exit code or signal ($?)\n"; - chomp $git_dir; - push @res, "--git-dir=$git_dir/.git"; - } - @res; -} - -{ - my $since_date; - my $until_date; - my $format_string = '%s%n%b%n'; - my $amend_file; - my $append_dot = 0; - my $cluster = 1; - my $ignore_matching; - my $ignore_line; - my $strip_tab = 0; - my $strip_cherry_pick = 0; - my $srcdir; - GetOptions - ( - help => sub { usage 0 }, - version => sub { print "$ME version $VERSION\n"; exit }, - 'since=s' => \$since_date, - 'until=s' => \$until_date, - 'format=s' => \$format_string, - 'amend=s' => \$amend_file, - 'append-dot' => \$append_dot, - 'cluster!' => \$cluster, - 'ignore-matching=s' => \$ignore_matching, - 'ignore-line=s' => \$ignore_line, - 'strip-tab' => \$strip_tab, - 'strip-cherry-pick' => \$strip_cherry_pick, - 'srcdir=s' => \$srcdir, - ) or usage 1; - - defined $since_date - and unshift @ARGV, "--since=$since_date"; - defined $until_date - and unshift @ARGV, "--until=$until_date"; - - # This is a hash that maps an SHA1 to perl code (i.e., s/old/new/) - # that makes a correction in the log or attribution of that commit. - my $amend_code = defined $amend_file ? parse_amend_file $amend_file : {}; - - my @cmd = ('git', - git_dir_option $srcdir, - qw(log --log-size), - '--pretty=format:%H:%ct %an <%ae>%n%n'.$format_string, @ARGV); - open PIPE, '-|', @cmd - or die ("$ME: failed to run '". quoted_cmd (@cmd) ."': $!\n" - . "(Is your Git too old? Version 1.5.1 or later is required.)\n"); - - my $prev_multi_paragraph; - my $prev_date_line = ''; - my @prev_coauthors = (); - my @skipshas = (); - while (1) - { - defined (my $in = ) - or last; - $in =~ /^log size (\d+)$/ - or die "$ME:$.: Invalid line (expected log size):\n$in"; - my $log_nbytes = $1; - - my $log; - my $n_read = read PIPE, $log, $log_nbytes; - $n_read == $log_nbytes - or die "$ME:$.: unexpected EOF\n"; - - # Extract leading hash. - my ($sha, $rest) = split ':', $log, 2; - defined $sha - or die "$ME:$.: malformed log entry\n"; - $sha =~ /^[0-9a-fA-F]{40}$/ - or die "$ME:$.: invalid SHA1: $sha\n"; - - my $skipflag = 0; - if (@skipshas) - { - foreach(@skipshas) - { - if ($sha =~ /^$_/) - { - $skipflag = $_; - last; - } - } - } - - # If this commit's log requires any transformation, do it now. - my $code = $amend_code->{$sha}; - if (defined $code) - { - eval 'use Safe'; - my $s = new Safe; - # Put the unpreprocessed entry into "$_". - $_ = $rest; - - # Let $code operate on it, safely. - my $r = $s->reval("$code") - or die "$ME:$.:$sha: failed to eval \"$code\":\n$@\n"; - - # Note that we've used this entry. - delete $amend_code->{$sha}; - - # Update $rest upon success. - $rest = $_; - } - - # Remove lines inserted by "git cherry-pick". - if ($strip_cherry_pick) - { - $rest =~ s/^\s*Conflicts:\n.*//sm; - $rest =~ s/^\s*\(cherry picked from commit [\da-f]+\)\n//m; - } - - my @line = split /[ \t]*\n/, $rest; - my $author_line = shift @line; - defined $author_line - or die "$ME:$.: unexpected EOF\n"; - $author_line =~ /^(\d+) (.*>)$/ - or die "$ME:$.: Invalid line " - . "(expected date/author/email):\n$author_line\n"; - - # Format 'Copyright-paperwork-exempt: Yes' as a standard ChangeLog - # `(tiny change)' annotation. - my $tiny = (grep (/^(?:Copyright-paperwork-exempt|Tiny-change):\s+[Yy]es$/, @line) - ? ' (tiny change)' : ''); - - my $date_line = sprintf "%s %s$tiny\n", - strftime ("%Y-%m-%d", localtime ($1)), $2; - - my @coauthors = grep /^Co-authored-by:.*$/, @line; - # Omit meta-data lines we've already interpreted. - @line = grep !/^(?:Signed-off-by:[ ].*>$ - |Co-authored-by:[ ] - |Copyright-paperwork-exempt:[ ] - |Tiny-change:[ ] - )/x, @line; - - # Remove leading and trailing blank lines. - if (@line) - { - while ($line[0] =~ /^\s*$/) { shift @line; } - while ($line[$#line] =~ /^\s*$/) { pop @line; } - } - - # Handle Emacs gitmerge.el "skipped" commits. - # Yes, this should be controlled by an option. So sue me. - if ( grep /^(; )?Merge from /, @line ) - { - my $found = 0; - foreach (@line) - { - if (grep /^The following commit.*skipped:$/, $_) - { - $found = 1; - ## Reset at each merge to reduce chance of false matches. - @skipshas = (); - next; - } - if ($found && $_ =~ /^([0-9a-fA-F]{7,}) [^ ]/) - { - push ( @skipshas, $1 ); - } - } - } - - # Ignore commits that match the --ignore-matching pattern, if specified. - if (defined $ignore_matching && @line && $line[0] =~ /$ignore_matching/) - { - $skipflag = 1; - } - elsif ($skipflag) - { - ## Perhaps only warn if a pattern matches more than once? - warn "$ME: warning: skipping $sha due to $skipflag\n"; - } - - if (! $skipflag) - { - if (defined $ignore_line && @line) - { - @line = grep ! /$ignore_line/, @line; - while ($line[$#line] =~ /^\s*$/) { pop @line; } - } - - # Record whether there are two or more paragraphs. - my $multi_paragraph = grep /^\s*$/, @line; - - # Format 'Co-authored-by: A U Thor ' lines in - # standard multi-author ChangeLog format. - for (@coauthors) - { - s/^Co-authored-by:\s*/\t /; - s/\s*/ - or warn "$ME: warning: missing email address for " - . substr ($_, 5) . "\n"; - } - - # If clustering of commit messages has been disabled, if this header - # would be different from the previous date/name/etc. header, - # or if this or the previous entry consists of two or more paragraphs, - # then print the header. - if ( ! $cluster - || $date_line ne $prev_date_line - || "@coauthors" ne "@prev_coauthors" - || $multi_paragraph - || $prev_multi_paragraph) - { - $prev_date_line eq '' - or print "\n"; - print $date_line; - @coauthors - and print join ("\n", @coauthors), "\n"; - } - $prev_date_line = $date_line; - @prev_coauthors = @coauthors; - $prev_multi_paragraph = $multi_paragraph; - - # If there were any lines - if (@line == 0) - { - warn "$ME: warning: empty commit message:\n $date_line\n"; - } - else - { - if ($append_dot) - { - # If the first line of the message has enough room, then - if (length $line[0] < 72) - { - # append a dot if there is no other punctuation or blank - # at the end. - $line[0] =~ /[[:punct:]\s]$/ - or $line[0] .= '.'; - } - } - - # Remove one additional leading TAB from each line. - $strip_tab - and map { s/^\t// } @line; - - # Prefix each non-empty line with a TAB. - @line = map { length $_ ? "\t$_" : '' } @line; - - print "\n", join ("\n", @line), "\n"; - } - } - - defined ($in = ) - or last; - $in ne "\n" - and die "$ME:$.: unexpected line:\n$in"; - } - - close PIPE - or die "$ME: error closing pipe from " . quoted_cmd (@cmd) . "\n"; - # FIXME-someday: include $PROCESS_STATUS in the diagnostic - - # Complain about any unused entry in the --amend=F specified file. - my $fail = 0; - foreach my $sha (keys %$amend_code) - { - warn "$ME:$amend_file: unused entry: $sha\n"; - $fail = 1; - } - - exit $fail; -} - -# Local Variables: -# mode: perl -# indent-tabs-mode: nil -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-start: "my $VERSION = '" -# time-stamp-format: "%:y-%02m-%02d %02H:%02M" -# time-stamp-time-zone: "UTC0" -# time-stamp-end: "'; # UTC" -# End: diff --git a/build-aux/gnu-web-doc-update b/build-aux/gnu-web-doc-update old mode 100755 new mode 100644 diff --git a/build-aux/gnupload b/build-aux/gnupload old mode 100755 new mode 100644 diff --git a/build-aux/guix.scm b/build-aux/guix.scm index 24927ad..72db610 100644 --- a/build-aux/guix.scm +++ b/build-aux/guix.scm @@ -38,17 +38,9 @@ (define %srcdir (or (current-source-directory) ".")) -(define (git-version-gen) - ;; Return a string containing Cuirass version number. - (let* ((cmd "git-version-gen .version") - (port (open-input-pipe (string-append %srcdir "/" cmd))) - (str (read-line port))) - (close-pipe port) - str)) - (package (inherit (specification->package "mcron2")) - (version (git-version-gen)) + (version "1.1.2") (source (local-file (dirname %srcdir) #:recursive? #t #:select? keep-mcron-file?)) (arguments diff --git a/configure.ac b/configure.ac old mode 100644 new mode 100755 index f7e3c34..07b75e6 --- a/configure.ac +++ b/configure.ac @@ -20,13 +20,10 @@ # along with GNU Mcron. If not, see . AC_PREREQ(2.61) -AC_INIT([GNU Mcron], - m4_esyscmd([build-aux/git-version-gen .tarball-version]), - [bug-mcron@gnu.org]) +AC_INIT([GNU Mcron], [1.1.2], [bug-mcron@gnu.org]) AC_CONFIG_SRCDIR([src/mcron.c]) AC_CONFIG_AUX_DIR([build-aux]) AC_REQUIRE_AUX_FILE([test-driver.scm]) -AC_REQUIRE_AUX_FILE([git-version-gen]) AM_INIT_AUTOMAKE([subdir-objects -Wall -Wno-override std-options]) AM_SILENT_RULES([yes]) # enables silent rules by default diff --git a/maint.mk b/maint.mk old mode 100644 new mode 100755 index e45ede1..3a41816 --- a/maint.mk +++ b/maint.mk @@ -37,7 +37,6 @@ sv_git_gl = 'https://$(git_sv_host)/gitweb/?p=gnulib.git;a=blob_plain;hb=HEAD;f= fetchfiles = \ $(sv_git_am)contrib/test-driver.scm \ $(sv_git_gl)build-aux/do-release-commit-and-tag \ - $(sv_git_gl)build-aux/gitlog-to-changelog \ ${sv_git_gl}build-aux/gnu-web-doc-update \ $(sv_git_gl)build-aux/gnupload From ba2975649aad5de50d1322c135550d8532d8358d Mon Sep 17 00:00:00 2001 From: Adam Tack Date: Mon, 11 Feb 2019 09:31:56 +0100 Subject: [PATCH 207/239] =?UTF-8?q?doc:=20Fix=20=E2=80=9CEvery=20second=20?= =?UTF-8?q?Sunday=E2=80=9D=20example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * doc/mcron.texi (Every second Sunday): If the first day of the month is Sunday, then the second Sunday of the month is seven days later not eight. --- doc/mcron.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/mcron.texi b/doc/mcron.texi index f408e11..c124bc8 100644 --- a/doc/mcron.texi +++ b/doc/mcron.texi @@ -434,7 +434,7 @@ the student to understand how this works!). (let* ((next-month (next-month-from current-time)) (first-day (tm:wday (localtime next-month))) (second-sunday (if (eqv? first-day 0) - 8 + 7 (- 14 first-day)))) (+ next-month (* 24 60 60 second-sunday)))) "my-program") From 7d4af7781f24d2220447006ff3d05f8e6ae3cceb Mon Sep 17 00:00:00 2001 From: Efraim Flashner Date: Sun, 7 Apr 2019 19:37:49 +0300 Subject: [PATCH 208/239] build: Update guix.scm * build-aux/guix.scm: Inherit from mcron. : Remove extra 'bootstrap phase. : Build with guile@2.2. : Add tzdata for tests. Signed-off-by: Mathieu Lirzin --- build-aux/guix.scm | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/build-aux/guix.scm b/build-aux/guix.scm index 72db610..c0bb6a8 100644 --- a/build-aux/guix.scm +++ b/build-aux/guix.scm @@ -1,6 +1,7 @@ ;;;; guix.scm -- Guix package definition ;;; Copyright © 2016 Mathieu Lirzin ;;; Copyright © 2018 宋文武 +;;; Copyright © 2019 Efraim Flashner ;;; ;;; This file is part of GNU Mcron. ;;; @@ -39,20 +40,16 @@ (or (current-source-directory) ".")) (package - (inherit (specification->package "mcron2")) + (inherit (specification->package "mcron")) (version "1.1.2") (source (local-file (dirname %srcdir) #:recursive? #t #:select? keep-mcron-file?)) - (arguments - '(#:phases - (modify-phases %standard-phases - (add-before 'configure 'bootstrap - (λ _ (zero? (system* "autoreconf" "-vfi"))))))) (inputs - `(("guile" ,(specification->package "guile@2.0")))) + `(("guile" ,(specification->package "guile@2.2")))) (native-inputs `(("autoconf" ,(specification->package "autoconf")) ("automake" ,(specification->package "automake")) ("help2man" ,(specification->package "help2man")) ("pkg-config" ,(specification->package "pkg-config")) - ("texinfo" ,(specification->package "texinfo"))))) + ("texinfo" ,(specification->package "texinfo")) + ("tzdata" ,(specification->package "tzdata"))))) From 3fdacd1393d75cd60061ebfbccd3448c51501c7f Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sun, 7 Apr 2019 23:18:34 +0200 Subject: [PATCH 209/239] maint: Add Efraim Flashner to the authors * AUTHORS: Add Efraim Flashner. --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 0668837..119ee00 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,3 +3,4 @@ Mathieu Lirzin Sergey Poznyakoff Ludovic Courtès 宋文武 +Efraim Flashner From a373317d96dc7191d8855d9a70106bf26d2c036b Mon Sep 17 00:00:00 2001 From: atsb Date: Sun, 17 Nov 2019 12:08:19 +0100 Subject: [PATCH 210/239] prepared files for 1.1.3 --- NEWS | 8 ++++++++ build-aux/guix.scm | 2 +- configure.ac | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 359f819..fc11c0c 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,13 @@ GNU Mcron NEWS -*- outline -*- +* Noteworthy changes in release 1.1.3 (2019-11-17) [stable] + +** Improvements + Package contains configure script by default + Authors file change (addition) + Doc fix for 'every second sunday' + guix.scm update + * Noteworthy changes in release 1.1.2 (2018-11-26) [stable] ** Improvements diff --git a/build-aux/guix.scm b/build-aux/guix.scm index c0bb6a8..53e9a63 100644 --- a/build-aux/guix.scm +++ b/build-aux/guix.scm @@ -41,7 +41,7 @@ (package (inherit (specification->package "mcron")) - (version "1.1.2") + (version "1.1.3") (source (local-file (dirname %srcdir) #:recursive? #t #:select? keep-mcron-file?)) (inputs diff --git a/configure.ac b/configure.ac index 07b75e6..438358e 100755 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # along with GNU Mcron. If not, see . AC_PREREQ(2.61) -AC_INIT([GNU Mcron], [1.1.2], [bug-mcron@gnu.org]) +AC_INIT([GNU Mcron], [1.1.3], [bug-mcron@gnu.org]) AC_CONFIG_SRCDIR([src/mcron.c]) AC_CONFIG_AUX_DIR([build-aux]) AC_REQUIRE_AUX_FILE([test-driver.scm]) From 2427317b108f928979fd3ea799174ceac80e18fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Sun, 23 Feb 2020 18:49:50 +0100 Subject: [PATCH 211/239] Add missing #include directives. in Guile 2.x used to include these, but this is no longer the case with 3.0. * src/cron.c, src/mcron.h: Include . * src/utils.c: Include . --- src/cron.c | 1 + src/mcron.c | 1 + src/utils.c | 1 + 3 files changed, 3 insertions(+) diff --git a/src/cron.c b/src/cron.c index 369f1d1..074f882 100644 --- a/src/cron.c +++ b/src/cron.c @@ -19,6 +19,7 @@ #include "utils.h" #include +#include /* Forward declarations. */ static void inner_main (void *closure, int argc, char *argv[]); diff --git a/src/mcron.c b/src/mcron.c index 22cc680..c0b151a 100644 --- a/src/mcron.c +++ b/src/mcron.c @@ -19,6 +19,7 @@ #include "utils.h" #include +#include /* Forward declarations. */ static void inner_main (void *closure, int argc, char *argv[]); diff --git a/src/utils.c b/src/utils.c index 3ea05f3..00a4150 100644 --- a/src/utils.c +++ b/src/utils.c @@ -18,6 +18,7 @@ #include "utils.h" #include +#include void wrap_env_path (const char *envar, const char *dir) From bedec44b397179c0eb1d11e52d0a6105015f6e38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Sun, 23 Feb 2020 18:49:51 +0100 Subject: [PATCH 212/239] build: Support Guile 3.0. * configure.ac: Add "3.0" to 'GUILE_PKG'. --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 438358e..4324a42 100755 --- a/configure.ac +++ b/configure.ac @@ -34,8 +34,8 @@ AM_PROG_CC_C_O AC_PROG_RANLIB AM_PROG_AR -# Check for Guile 2.x. development files -GUILE_PKG([2.2 2.0]) +# Check for Guile development files. +GUILE_PKG([3.0 2.2 2.0]) # Set Guile flags without using GUILE_FLAGS which is requiring the unused # 'config.rpath' script. From 8ae1e8c92e88308a6f1a7107acdf17e5526d4e89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Sun, 23 Feb 2020 18:49:52 +0100 Subject: [PATCH 213/239] base: Call 'child-cleanup' when 'select' returns an empty set. Previously, on Guile >= 2.2, we'd lose this opportunity to call 'child-cleanup', possibly leaving zombies behind us. * src/mcron/base.scm (run-job-loop): Define 'select*'. Don't expect 'select*' to throw upon EINTR or EAGAIN. --- src/mcron/base.scm | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/mcron/base.scm b/src/mcron/base.scm index 17ddd5c..572d45b 100644 --- a/src/mcron/base.scm +++ b/src/mcron/base.scm @@ -1,7 +1,7 @@ ;;;; base.scm -- core procedures ;;; Copyright © 2003 Dale Mellor ;;; Copyright © 2015, 2016, 2018 Mathieu Lirzin -;;; Copyright © 2016 Ludovic Courtès +;;; Copyright © 2016, 2020 Ludovic Courtès ;;; ;;; This file is part of GNU Mcron. ;;; @@ -210,6 +210,20 @@ next value." ;; case we break out of the loop here, and let the main procedure deal with ;; the situation (it will eventually re-call this function, thus maintaining ;; the loop). + (cond-expand + ((or guile-3.0 guile-2.2) ;2.2 and 3.0 + (define select* select)) + (else + ;; On Guile 2.0, 'select' could throw upon EINTR or EAGAIN. + (define (select* read write except time) + (catch 'system-error + (lambda () + (select read write except time)) + (lambda args + (if (member (system-error-errno args) (list EAGAIN EINTR)) + '(() () ()) + (apply throw args))))))) + (call-with-current-continuation (lambda (break) (let loop () @@ -218,19 +232,17 @@ next value." (let ((sleep-time (if next-time (- next-time (current-time)) 2000000000))) - (when (and - (> sleep-time 0) - (not (null? (catch 'system-error - (λ () - (car (select fd-list '() '() sleep-time))) - (λ (key . args) - (let ((err (car (last args)))) - (cond ((member err (list EINTR EAGAIN)) - (child-cleanup) - '()) - (else - (apply throw key args))))))))) - (break)) + (when (> sleep-time 0) + (match (select* fd-list '() '() sleep-time) + ((() () ()) + ;; 'select' returned an empty set, perhaps because it got + ;; EINTR or EAGAIN. It's a good time to wait for child + ;; processes. + (child-cleanup)) + (((lst ...) () ()) + ;; There's some activity so leave the loop. + (break)))) + (for-each run-job next-jobs-lst) (child-cleanup) (loop)))))))) From 5794ea5a5b58344d375b3d099d51429040b9c1bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Sun, 23 Feb 2020 18:49:53 +0100 Subject: [PATCH 214/239] base: Avoid 'call-with-current-continuation'. 'call-with-current-continuation' is overkill and not quite what we want. 'let/ec' is supported in Guile 2.0, 2.2, and 3.0. * src/mcron/base.scm (run-job-loop): Use 'let/ec' instead of 'call-with-current-continuation'. --- src/mcron/base.scm | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/mcron/base.scm b/src/mcron/base.scm index 572d45b..edcf1bc 100644 --- a/src/mcron/base.scm +++ b/src/mcron/base.scm @@ -27,6 +27,7 @@ (define-module (mcron base) #:use-module (ice-9 match) + #:use-module (ice-9 control) #:use-module (mcron environment) #:use-module (mcron utils) #:use-module (srfi srfi-1) @@ -224,25 +225,24 @@ next value." '(() () ()) (apply throw args))))))) - (call-with-current-continuation - (lambda (break) - (let loop () - (match (find-next-jobs #:schedule schedule) - ((next-time . next-jobs-lst) - (let ((sleep-time (if next-time - (- next-time (current-time)) - 2000000000))) - (when (> sleep-time 0) - (match (select* fd-list '() '() sleep-time) - ((() () ()) - ;; 'select' returned an empty set, perhaps because it got - ;; EINTR or EAGAIN. It's a good time to wait for child - ;; processes. - (child-cleanup)) - (((lst ...) () ()) - ;; There's some activity so leave the loop. - (break)))) + (let/ec break + (let loop () + (match (find-next-jobs #:schedule schedule) + ((next-time . next-jobs-lst) + (let ((sleep-time (if next-time + (- next-time (current-time)) + 2000000000))) + (when (> sleep-time 0) + (match (select* fd-list '() '() sleep-time) + ((() () ()) + ;; 'select' returned an empty set, perhaps because it got + ;; EINTR or EAGAIN. It's a good time to wait for child + ;; processes. + (child-cleanup)) + (((lst ...) () ()) + ;; There's some activity so leave the loop. + (break)))) - (for-each run-job next-jobs-lst) - (child-cleanup) - (loop)))))))) + (for-each run-job next-jobs-lst) + (child-cleanup) + (loop))))))) From fb1d663383602aa9eac1c28d0f763001a43849c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Sun, 23 Feb 2020 18:49:54 +0100 Subject: [PATCH 215/239] utils: It's 2020! * src/mcron/utils.scm (show-version): Update copyright year. --- src/mcron/utils.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mcron/utils.scm b/src/mcron/utils.scm index 00cf0c5..d8b1dc7 100644 --- a/src/mcron/utils.scm +++ b/src/mcron/utils.scm @@ -56,7 +56,7 @@ and exit with its error code." (short-name (cadr (string-split name #\space))) (version config-package-version)) (simple-format #t "~a (~a) ~a -Copyright (C) 2018 the ~a authors. +Copyright (C) 2020 the ~a authors. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.\n" From 56308568da1c846698a4b2ad593a164133ab19cf Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Thu, 27 Feb 2020 21:16:39 +0000 Subject: [PATCH 216/239] Updated my e-mail address. --- AUTHORS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 119ee00..5657aa1 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,4 +1,4 @@ -Dale Mellor +Dale Mellor Mathieu Lirzin Sergey Poznyakoff Ludovic Courtès From bd37306294154610ad63426299e63b6bae5f4942 Mon Sep 17 00:00:00 2001 From: atsb Date: Sun, 12 Apr 2020 14:54:24 +0200 Subject: [PATCH 217/239] preparing 1.1.4 --- NEWS | 10 ++++++++++ build-aux/guix.scm | 2 +- configure.ac | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index fc11c0c..f8d0d73 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,15 @@ GNU Mcron NEWS -*- outline -*- +* Noteworthy changes in release 1.1.4 (2020-04-12) [stable] + +** Improvements + Added missing #include directives + Support Guile 3.0 + Call 'child-cleanup' when 'select' returns an empty set + Avoid 'call-with-current-continuation' + Date changes for Copyrights changed for 2020 + Email updates in documentation + * Noteworthy changes in release 1.1.3 (2019-11-17) [stable] ** Improvements diff --git a/build-aux/guix.scm b/build-aux/guix.scm index 53e9a63..ae253ec 100644 --- a/build-aux/guix.scm +++ b/build-aux/guix.scm @@ -41,7 +41,7 @@ (package (inherit (specification->package "mcron")) - (version "1.1.3") + (version "1.1.4") (source (local-file (dirname %srcdir) #:recursive? #t #:select? keep-mcron-file?)) (inputs diff --git a/configure.ac b/configure.ac index 4324a42..768a94c 100755 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # along with GNU Mcron. If not, see . AC_PREREQ(2.61) -AC_INIT([GNU Mcron], [1.1.3], [bug-mcron@gnu.org]) +AC_INIT([GNU Mcron], [1.1.4], [bug-mcron@gnu.org]) AC_CONFIG_SRCDIR([src/mcron.c]) AC_CONFIG_AUX_DIR([build-aux]) AC_REQUIRE_AUX_FILE([test-driver.scm]) From f22de155b8e75918c9030897a01e070a8af02661 Mon Sep 17 00:00:00 2001 From: atsb Date: Tue, 14 Apr 2020 22:10:28 +0200 Subject: [PATCH 218/239] small fix for older gcc versions --- src/mcron.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mcron.c b/src/mcron.c index c0b151a..adb91aa 100644 --- a/src/mcron.c +++ b/src/mcron.c @@ -110,8 +110,9 @@ parse_opt (int key, char *arg, struct argp_state *state) SCM lst = SCM_EOL; int filec = state->argc - state->next; char **filev = state->argv + state->next; + int i; - for (int i = filec - 1; i >= 0; i--) + for (i = filec - 1; i >= 0; i--) lst = scm_cons (scm_from_locale_string (filev[i]), lst); assq_symbol_set_x (config, "files", lst); From a8d938c4ed93aa03fc87c9173aaee4e26ee67c5b Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Mon, 20 Apr 2020 11:27:53 +0000 Subject: [PATCH 219/239] test: make date tests reliable, i.e. independent of current time Some of the date tests depend both on the particular time of day and year at which the test is run, and also on the state of daylight-savings adjustments. (At the present time on my system there are four failing tests, but YMMV.) This patch puts all the tests to UTC time in the C locale, making the results consistent. *All* items in the test suite should be passing once again. * tests/job-schedule.scm: Fix up the environment before running the tests. --- tests/job-specifier.scm | 32 ++++++++++++++------------------ tests/schedule.sh | 3 +++ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/tests/job-specifier.scm b/tests/job-specifier.scm index baf96af..70dd518 100644 --- a/tests/job-specifier.scm +++ b/tests/job-specifier.scm @@ -56,36 +56,32 @@ ;;; TODO: Find more meaningful date examples. +(setenv "TZ" ":UTC") + (test-equal "next-year" - (list 59989762800 1546293600) - (list (next-year '(1971)) + (list 1893456000 1546300800) + (list (next-year '(130)) ;; This is the year 2030. (next-year-from 1522095469))) (test-equal "next-month" - (list 28854000 5094000) - (list (next-month '(11)) - (next-month-from 101 '(0 2 4)))) + 5097600 + (next-month-from 101 '(0 2 4))) (test-equal "next-day" - (list 2588400 342000) - (list (next-day '(31)) - (next-day-from 4337 '(0 5 10)))) + 345600 + (next-day-from 4337 '(0 5 10))) (test-equal "next-hour" - '(3600 82800 3600) - (list (next-hour) - (next-hour '(0)) - (next-hour-from 3 '(0 1 2 3 4)))) + 3600 + (next-hour-from 3 '(0 1 2 3 4))) (test-equal "next-minute" - '(240 60) - (list (next-minute '(4 9)) - (next-minute-from 8))) + 60 + (next-minute-from 8)) (test-equal "next-second" - '(52 15) - (list (next-second '(52 55)) - (next-second-from 14))) + 15 + (next-second-from 14)) ;;; ;;; Check 'configuration-user' manipulation diff --git a/tests/schedule.sh b/tests/schedule.sh index d403f1d..9a1836e 100644 --- a/tests/schedule.sh +++ b/tests/schedule.sh @@ -26,6 +26,9 @@ export SOURCE_DATE_EPOCH TZ=UTC0 export TZ +LC_ALL=C +export LC_ALL + # Use current working directory to store mcron files XDG_CONFIG_HOME=`pwd` export XDG_CONFIG_HOME From cb88cc9e423ce02c3e2806e8a7889c3048264a25 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Fri, 10 Apr 2020 19:38:07 +0100 Subject: [PATCH 220/239] doc/mcron.texi: Make the manual gender-neutral. Replace his/hers with theirs, etc. *doc/mcron.text: light edits only. --- doc/mcron.texi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/mcron.texi b/doc/mcron.texi index c124bc8..70ab38c 100644 --- a/doc/mcron.texi +++ b/doc/mcron.texi @@ -158,10 +158,10 @@ example, take the system load into consideration. Turns out to be easy to provide complete backwards compatibility with Vixie cron. @item -Each user looks after his own files in his own directory. He can use +Each user looks after their own files in their own directory. They can use more than one to break up complicated cron specifications. @item -Each user can run his own daemon. This removes the need for suid +Each user can run their own daemon. This removes the need for suid programs to manipulate the crontabs, and eliminates many security concerns that surround all existing cron programs. @item @@ -516,7 +516,7 @@ second-to-last day of every month. @emph{NOTE} that this section is definitive. If there is a difference in behaviour between the mcron program and this part of the manual, then there is a bug in the program. This section is also copied verbatim -from Paul Vixie's documentation for his cron program, and his +from Paul Vixie's documentation for their cron program, and their copyright notice is duly reproduced below. There are three problems with this specification. @@ -815,7 +815,7 @@ place in the part which implements the mcron personality. @cindex mcron arguments @cindex command line, mcron @cindex mcron command line -Mcron should be run by the user who wants to schedule his jobs. It +Mcron should be run by the user who wants to schedule their jobs. It may be made a background job using the facilities of the shell. The basic command is @code{mcron [OPTION ...] [file ...]} which has the effect of reading all the configuration files specified (subject to @@ -1026,7 +1026,7 @@ Delete the user's crontab file, and exit. @item -e @item --edit Using the editor specified in the user's VISUAL or EDITOR environment -variables, allow the user to edit his crontab. Once the user exits the +variables, allow the user to edit their crontab. Once the user exits the editor, the crontab is checked for parseability, and if it is okay then it is installed as the user's new crontab and the daemon is notified that a change has taken place, so that the new file will @@ -1231,7 +1231,7 @@ the mcron base. @deffn{Scheme procedure} remove-user-jobs user @ [#:schedule @var{%global-schedule}] -The argument @var{user} should be a string naming a user (his +The argument @var{user} should be a string naming a user (their login name), or an integer UID, or an object representing the user's passwd entry. All jobs on the current job list that are scheduled to be run under this personality are removed from the job list. From ad6e4e550512555328cfbc8f2777e71f5d0e28a4 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Mon, 13 Apr 2020 19:45:45 +0100 Subject: [PATCH 221/239] test: Demonstration of failure to open local file. The mcron program goes looking for files specified on the command line in Guile's module path, inevitably resulting in failure to load said file. Running 'make check' will show at least one failure. * tests/basic.sh: Added new test. --- tests/basic.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/basic.sh b/tests/basic.sh index 07b664b..7b2ca55 100644 --- a/tests/basic.sh +++ b/tests/basic.sh @@ -27,6 +27,9 @@ cat > cron/foo.guile < "output$$" +grep -e "foo" "output$$" || fail_ "'foo.guile' job is not scheduled" + mcron --schedule=1 > "output$$" grep -e "foo" "output$$" || fail_ "'foo.guile' job is not scheduled" From deaa79a7c687ebc3eb3bb6c318a8e11de154efcb Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Mon, 13 Apr 2020 20:05:27 +0100 Subject: [PATCH 222/239] mcron: Look for local files in local directory. Previously were looking for files listed on the command line in Guile's modules directory. This is a bug-fix; running 'make check' will reveal one less failure than before. * src/mcron/scripts/mcron.scm (process-user-file): use read and eval instead of load. --- src/mcron/scripts/mcron.scm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mcron/scripts/mcron.scm b/src/mcron/scripts/mcron.scm index 6545ada..8ae61cf 100644 --- a/src/mcron/scripts/mcron.scm +++ b/src/mcron/scripts/mcron.scm @@ -19,6 +19,7 @@ (define-module (mcron scripts mcron) #:use-module (ice-9 ftw) + #:use-module (ice-9 rdelim) #:use-module (mcron base) #:use-module (mcron config) #:use-module (mcron job-specifier) ;for user/system files @@ -36,9 +37,11 @@ silently ignored." (cond ((string=? "-" file-name) (if (string=? input "vixie") (read-vixie-port (current-input-port)) - (eval-string (read-string)))) + (eval-string (read-string) + (resolve-module '(mcron job-specifier))))) ((or guile-syntax? (regexp-exec guile-regexp file-name)) - (load file-name)) + (eval-string (read-delimited "" (open-input-file file-name)) + (resolve-module '(mcron job-specifier)))) ((regexp-exec vixie-regexp file-name) (read-vixie-file file-name)))))) From 4a05a2e8612560cd7f3274d2930e86bfc9f1ec93 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Mon, 20 Apr 2020 16:25:19 +0000 Subject: [PATCH 223/239] test: demonstrate incorrect -s option on mcron program The option is supposed to be able to take an optional argument, but if the argument is not supplied (should default to 8) then the test, rather than failing, is skipped with a friendly message in the log file. The proper fix will come with an upstream patch to GNU Guile, and a future version of Mcron. * tests/schedule-2.sh: new test, new file * Makefile.am: make sure to run the new test file --- Makefile.am | 1 + tests/schedule-2.sh | 82 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 tests/schedule-2.sh diff --git a/Makefile.am b/Makefile.am index 38b0a7b..972e2c6 100755 --- a/Makefile.am +++ b/Makefile.am @@ -136,6 +136,7 @@ SCM_LOG_DRIVER = \ TESTS = \ tests/basic.sh \ tests/schedule.sh \ + tests/schedule-2.sh \ tests/base.scm \ tests/environment.scm \ tests/job-specifier.scm \ diff --git a/tests/schedule-2.sh b/tests/schedule-2.sh new file mode 100644 index 0000000..7039123 --- /dev/null +++ b/tests/schedule-2.sh @@ -0,0 +1,82 @@ +# schedule-2.sh -- Check mcron schedule output +# Copyright © 2020 Dale Mellor +# +# This file is part of GNU Mcron. +# +# GNU Mcron is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNU Mcron is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Mcron. If not, see . + +source "${srcdir}/tests/init.sh" + +# Use UTC and SOURCE_DATE_EPOCH to get reproducible result. + +SOURCE_DATE_EPOCH=1 +export SOURCE_DATE_EPOCH + +TZ=UTC0 +export TZ + +LC_ALL=C +export LC_ALL + +# Use current working directory to store mcron files +XDG_CONFIG_HOME=`pwd` +export XDG_CONFIG_HOME + +mkdir cron +cat > cron/foo.guile < expected < output-A +diff expected output-A \ + || skip_ 'The -s option is not fully functional; +this will be fixed with a future version of GNU Guile and then +a future version of GNU Mcron.' + +Exit 0 From 1eedf3b6d24f421ccdb8798b053ee718d1051651 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Mon, 13 Apr 2020 11:42:39 +0100 Subject: [PATCH 224/239] project: banish need for C compiler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch gets rid of the thin veneer that we currently have around the three executables. This was done for historical reasons (circa 2003 Guile couldnʼt deal with process signals and forks). In fact these problems were fixed many moons ago, and there is now no need for it. The project becomes 100% Guile! Many files are affected; interested coders should use the GIT repository to understand the details of all the changes. --- Makefile.am | 75 ++++++++++---------- build-aux/guix.scm | 8 +-- configure.ac | 55 +++++++-------- src/cron.c | 80 ---------------------- src/cron.in | 8 +++ src/crontab.c | 48 ------------- src/crontab.in | 7 ++ src/mcron.c | 125 ---------------------------------- src/mcron.in | 8 +++ src/mcron/base.scm | 2 +- src/mcron/job-specifier.scm | 19 +++--- src/mcron/scripts/cron.scm | 114 ++++++++++++++++++------------- src/mcron/scripts/crontab.scm | 4 +- src/mcron/scripts/mcron.scm | 103 ++++++++++++++++++++-------- src/utils.c | 48 ------------- src/utils.h | 33 --------- tests/schedule-2.sh | 13 ++-- 17 files changed, 248 insertions(+), 502 deletions(-) delete mode 100644 src/cron.c create mode 100644 src/cron.in delete mode 100644 src/crontab.c create mode 100644 src/crontab.in delete mode 100644 src/mcron.c create mode 100644 src/mcron.in delete mode 100644 src/utils.c delete mode 100644 src/utils.h diff --git a/Makefile.am b/Makefile.am index 972e2c6..e8fe80c 100755 --- a/Makefile.am +++ b/Makefile.am @@ -21,40 +21,18 @@ ## Programs. ## ## ---------- ## -bin_PROGRAMS = bin/mcron +bin_SCRIPTS = bin/mcron +noinst_SCRIPTS = if MULTI_USER -bin_PROGRAMS += bin/crontab -sbin_PROGRAMS = bin/cron +bin_SCRIPTS += bin/crontab +sbin_SCRIPTS = bin/cron else -noinst_PROGRAMS = bin/cron bin/crontab +noinst_SCRIPTS += bin/cron bin/crontab endif -AM_CPPFLAGS = \ - -DPACKAGE_LOAD_PATH=\"$(guilesitedir)\" \ - -DPACKAGE_LOAD_COMPILED_PATH=\"$(guilesitegodir)\" \ - -D_GNU_SOURCE - -AM_CFLAGS = @GUILE_CFLAGS@ -LDADD = @GUILE_LIBS@ src/libmcron.a - -bin_mcron_SOURCES = src/mcron.c -bin_mcron_DEPENDENCIES = $(compiled_modules) $(noinst_LIBRARIES) - -bin_cron_SOURCES = src/cron.c -bin_cron_DEPENDENCIES = $(compiled_modules) $(noinst_LIBRARIES) - -bin_crontab_SOURCES = src/crontab.c -bin_crontab_DEPENDENCIES = $(compiled_modules) $(noinst_LIBRARIES) - # wrapper to be used in the build environment and for running tests. -noinst_SCRIPTS = pre-inst-env - -# local library. -noinst_LIBRARIES = src/libmcron.a -src_libmcron_a_SOURCES = \ - src/utils.c \ - src/utils.h +noinst_SCRIPTS += pre-inst-env ## --------------- ## ## Guile modules. ## @@ -97,7 +75,7 @@ compiled_modules = \ $(pkgmodulego_DATA) \ $(pkgscriptgo_DATA) -CLEANFILES = $(compiled_modules) +CLEANFILES = $(compiled_modules) bin/crontab bin/cron bin/mcron DISTCLEANFILES = src/mcron/config.scm # Unset 'GUILE_LOAD_COMPILED_PATH' altogether while compiling. Otherwise, if @@ -120,6 +98,24 @@ DISTCLEANFILES = src/mcron/config.scm --warn=format --warn=unbound-variable --warn=arity-mismatch \ --target="$(host)" --output="$@" "$<" $(devnull_verbose) + +bin/% : src/%.in Makefile + -@sed -e 's,%PREFIX%,${prefix},g' \ + -e 's,%modsrcdir%,${guilesitedir},g' \ + -e 's,%modbuilddir%,${guilesitegodir},g' \ + -e 's,%localstatedir%,${localstatedir},g' \ + -e 's,%pkglibdir%,${pkglibdir},g' \ + -e 's,%sysconfdir%,${sysconfdir},g' \ + -e 's,%localedir%,${localedir},g' \ + -e 's,%VERSION%,@VERSION@,g' \ + -e 's,%PACKAGE_BUGREPORT%,@PACKAGE_BUGREPORT@,g' \ + -e 's,%PACKAGE_NAME%,@PACKAGE_NAME@,g' \ + -e 's,%PACKAGE_URL%,@PACKAGE_URL@,g' \ + -e 's,%GUILE%,$(GUILE),g' \ + $< > $@; + -@chmod a+x $@ + + ## ------------ ## ## Test suite. ## ## ------------ ## @@ -161,25 +157,28 @@ EXTRA_DIST = \ # Sed command for Transforming program names. transform_exe = s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/ -if MULTI_USER install-exec-hook: - tcrontab=`echo crontab$(EXEEXT) | sed '$(transform_exe)'`; \ +if MULTI_USER + tcrontab=`echo crontab | sed '$(transform_exe)'`; \ chmod u+s $(DESTDIR)$(bindir)/$${tcrontab} + tcron=`echo cron | sed '$(transform_exe)'`; \ + chmod u+s $(DESTDIR)$(sbindir)/$${tcron} endif + tmcron=`echo mcron | sed '$(transform_exe)'`; installcheck-local: ## Check that only expected programs are installed and configured - tmcron=`echo mcron$(EXEEXT) | sed '$(transform_exe)'`; \ + tmcron=`echo mcron | sed '$(transform_exe)'`; \ test -e $(DESTDIR)$(bindir)/$${tmcron} if MULTI_USER - tcrontab=`echo crontab$(EXEEXT) | sed '$(transform_exe)'`; \ + tcrontab=`echo crontab | sed '$(transform_exe)'`; \ test -u $(DESTDIR)$(bindir)/$${tcrontab} - tcron=`echo cron$(EXEEXT) | sed '$(transform_exe)'`; \ + tcron=`echo cron | sed '$(transform_exe)'`; \ test -e $(DESTDIR)$(sbindir)/$${tcron} else !MULTI_USER - tcrontab=`echo crontab$(EXEEXT) | sed '$(transform_exe)'`; \ + tcrontab=`echo crontab | sed '$(transform_exe)'`; \ test ! -u $(DESTDIR)$(bindir)/$${tcrontab} - tcron=`echo cron$(EXEEXT) | sed '$(transform_exe)'`; \ + tcron=`echo cron | sed '$(transform_exe)'`; \ test ! -f $(DESTDIR)$(sbindir)/$${tcron} endif !MULTI_USER @@ -220,10 +219,10 @@ gen_man = \ esac $(srcdir)/doc/mcron.1: src/mcron/scripts/mcron.scm bin/mcron - -@prog="mcron"; man_section=1; $(gen_man) + -@prog="bin/mcron"; man_section=1; $(gen_man) $(srcdir)/doc/crontab.1: src/mcron/scripts/crontab.scm bin/crontab - -@prog="crontab"; man_section=1; $(gen_man) + -@prog="bin/crontab"; man_section=1; $(gen_man) $(srcdir)/doc/cron.8: src/mcron/scripts/cron.scm bin/cron -@prog="cron"; man_section=8; $(gen_man) diff --git a/build-aux/guix.scm b/build-aux/guix.scm index ae253ec..3c57bf1 100644 --- a/build-aux/guix.scm +++ b/build-aux/guix.scm @@ -32,16 +32,16 @@ '(".git" "autom4te" "Makefile.in" ".go" ".log" "stamp-vti" ".dirstamp")) (any (λ (str) (string-suffix? str file)) - '("trs""configure" "Makefile" "config.status" "pre-inst-env" - "aclocal.m4" "bin/cron" "bin/mcron" "bin/crontab" "config.cache" - "guix.scm"))))) + '("trs" "configure" "Makefile" "config.status" "pre-inst-env" + "aclocal.m4" "bin/cron" "bin/mcron" "bin/crontab" + "config.cache" "guix.scm"))))) (define %srcdir (or (current-source-directory) ".")) (package (inherit (specification->package "mcron")) - (version "1.1.4") + (version "1.1.4+") (source (local-file (dirname %srcdir) #:recursive? #t #:select? keep-mcron-file?)) (inputs diff --git a/configure.ac b/configure.ac index 768a94c..fb19229 100755 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ ## Process this file with autoconf to produce a configure script. -# Copyright © 2003, 2005, 2012, 2014 Dale Mellor -# +# +# Copyright © 2003, 2005, 2012, 2014 Dale Mellor # Copyright © 2015, 2016, 2017, 2018 Mathieu Lirzin # Copyright © 2018 宋文武 # @@ -20,19 +20,18 @@ # along with GNU Mcron. If not, see . AC_PREREQ(2.61) -AC_INIT([GNU Mcron], [1.1.4], [bug-mcron@gnu.org]) -AC_CONFIG_SRCDIR([src/mcron.c]) +AC_INIT([GNU Mcron], [1.1.4+], [bug-mcron@gnu.org]) +AC_CONFIG_SRCDIR([src/mcron/scripts/mcron.scm]) AC_CONFIG_AUX_DIR([build-aux]) AC_REQUIRE_AUX_FILE([test-driver.scm]) -AM_INIT_AUTOMAKE([subdir-objects -Wall -Wno-override std-options]) -AM_SILENT_RULES([yes]) # enables silent rules by default + +dnl We're fine with GNU make constructs, hence '-Wno-portability'. +AM_INIT_AUTOMAKE([1.11 gnu silent-rules subdir-objects color-tests + -Wall -Wno-override -Wno-portability std-options]) + +AM_SILENT_RULES([yes]) # Enables silent rules by default. AC_CANONICAL_HOST -AC_PROG_AWK -AC_PROG_EGREP -AM_PROG_CC_C_O -AC_PROG_RANLIB -AM_PROG_AR # Check for Guile development files. GUILE_PKG([3.0 2.2 2.0]) @@ -41,12 +40,6 @@ GUILE_PKG([3.0 2.2 2.0]) # 'config.rpath' script. PKG_CHECK_MODULES(GUILE, [guile-$GUILE_EFFECTIVE_VERSION]) -# Check for 'argp' program arguments parser. -AC_CHECK_FUNC(argp_parse, [], AC_MSG_ERROR([argp not found])) - -# Check for non-POSIX string formatting function. -AC_CHECK_FUNC(asprintf, [], AC_MSG_ERROR([asprintf not found])) - # Checks for programs. GUILE_PROGS @@ -76,8 +69,8 @@ AC_MSG_CHECKING([which spool directory to use]) AC_ARG_WITH(spool-dir, AC_HELP_STRING([--with-spool-dir], [the crontab spool directory (/var/cron/tabs)]), - CONFIG_SPOOL_DIR=$withval, - CONFIG_SPOOL_DIR=[/var/cron/tabs]) + CONFIG_SPOOL_DIR=$withval, + CONFIG_SPOOL_DIR=[/var/cron/tabs]) AC_MSG_RESULT($CONFIG_SPOOL_DIR) AC_SUBST(CONFIG_SPOOL_DIR) @@ -85,8 +78,8 @@ AC_MSG_CHECKING([name of socket]) AC_ARG_WITH(socket-file, AC_HELP_STRING([--with-socket-file], [unix pathname for cron socket (/var/cron/socket)]), - CONFIG_SOCKET_FILE=$withval, - CONFIG_SOCKET_FILE=[/var/cron/socket]) + CONFIG_SOCKET_FILE=$withval, + CONFIG_SOCKET_FILE=[/var/cron/socket]) AC_MSG_RESULT($CONFIG_SOCKET_FILE) AC_SUBST(CONFIG_SOCKET_FILE) @@ -94,8 +87,8 @@ AC_MSG_CHECKING([name of allow file]) AC_ARG_WITH(allow-file, AC_HELP_STRING([--with-allow-file], [the file of allowed users (/var/cron/allow)]), - CONFIG_ALLOW_FILE=$withval, - CONFIG_ALLOW_FILE=[/var/cron/allow]) + CONFIG_ALLOW_FILE=$withval, + CONFIG_ALLOW_FILE=[/var/cron/allow]) AC_MSG_RESULT($CONFIG_ALLOW_FILE) AC_SUBST(CONFIG_ALLOW_FILE) @@ -103,8 +96,8 @@ AC_MSG_CHECKING([name of deny file]) AC_ARG_WITH(deny-file, AC_HELP_STRING([--with-deny-file], [the file of barred users (/var/cron/deny)]), - CONFIG_DENY_FILE=$withval, - CONFIG_DENY_FILE=[/var/cron/deny]) + CONFIG_DENY_FILE=$withval, + CONFIG_DENY_FILE=[/var/cron/deny]) AC_MSG_RESULT($CONFIG_DENY_FILE) AC_SUBST(CONFIG_DENY_FILE) @@ -112,8 +105,8 @@ AC_MSG_CHECKING([name of PID file]) AC_ARG_WITH(pid-file, AC_HELP_STRING([--with-pid-file], [the file to record cron's PID (/var/run/cron.pid)]), - CONFIG_PID_FILE=$withval, - CONFIG_PID_FILE=[/var/run/cron.pid]) + CONFIG_PID_FILE=$withval, + CONFIG_PID_FILE=[/var/run/cron.pid]) AC_MSG_RESULT($CONFIG_PID_FILE) AC_SUBST(CONFIG_PID_FILE) @@ -121,19 +114,19 @@ AC_MSG_CHECKING([directory to hold temporary files]) AC_ARG_WITH(tmp-dir, AC_HELP_STRING([--with-tmp-dir], [directory to hold temporary files (/tmp)]), - CONFIG_TMP_DIR=$withval, - CONFIG_TMP_DIR=[/tmp]) + CONFIG_TMP_DIR=$withval, + CONFIG_TMP_DIR=[/tmp]) AC_MSG_RESULT($CONFIG_TMP_DIR) AC_SUBST(CONFIG_TMP_DIR) # Include the Maintainer's Makefile fragment, if it's here. MAINT_MAKEFILE=/dev/null AS_IF([test -r "$srcdir/maint.mk"], - [MAINT_MAKEFILE="$srcdir/maint.mk"]) + [MAINT_MAKEFILE="$srcdir/maint.mk"]) AC_SUBST_FILE([MAINT_MAKEFILE]) AC_CONFIG_FILES([pre-inst-env:build-aux/pre-inst-env.in], - [chmod +x pre-inst-env]) + [chmod +x pre-inst-env]) AC_CONFIG_FILES([doc/config.texi Makefile src/mcron/config.scm]) diff --git a/src/cron.c b/src/cron.c deleted file mode 100644 index 074f882..0000000 --- a/src/cron.c +++ /dev/null @@ -1,80 +0,0 @@ -/* cron.c -- run jobs at scheduled times - Copyright © 2003, 2014 Dale Mellor - Copyright © 2015, 2016, 2017 Mathieu Lirzin - - This file is part of GNU Mcron. - - GNU Mcron is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - GNU Mcron is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNU Mcron. If not, see . */ - -#include "utils.h" -#include -#include - -/* Forward declarations. */ -static void inner_main (void *closure, int argc, char *argv[]); -static void react_to_terminal_signal (int sig); -static SCM set_cron_signals (void); - -int -main (int argc, char *argv[]) -{ - /* Set Guile load paths to ensure that Mcron modules will be found after - installation. In a build environment let the 'pre-inst-env' script set - the correct paths. */ - if (getenv ("MCRON_UNINSTALLED") == NULL) - { - wrap_env_path ("GUILE_LOAD_PATH", PACKAGE_LOAD_PATH); - wrap_env_path ("GUILE_LOAD_COMPILED_PATH", PACKAGE_LOAD_COMPILED_PATH); - } - - scm_boot_guile (argc, argv, inner_main, NULL); - - return EXIT_SUCCESS; -} - -/* Launch the Mcron Guile main program. */ -static void -inner_main (void *closure, int argc, char *argv[]) -{ - scm_set_current_module (scm_c_resolve_module ("mcron scripts cron")); - scm_c_define_gsubr ("c-set-cron-signals", 0, 0, 0, set_cron_signals); - scm_call_0 (scm_variable_ref (scm_c_lookup ("main"))); -} - -/* Set up all the signal handlers. This is necessary to perform the signal - processing in C because the sigaction function won't work when called from - Guile. */ -static SCM -set_cron_signals () -{ - static struct sigaction sa; - - memset (&sa, 0, sizeof (sa)); - sa.sa_handler = react_to_terminal_signal; - sigaction (SIGTERM, &sa, 0); - sigaction (SIGINT, &sa, 0); - sigaction (SIGQUIT, &sa, 0); - sigaction (SIGHUP, &sa, 0); - - return SCM_BOOL_T; -} - -/* Handle signal SIG and exit. All signals that cron handles will produce the - same behavior so we don't need to use SIG in the implementation. */ -static void -react_to_terminal_signal (int sig) -{ - scm_c_eval_string ("(delete-run-file)"); - exit (EXIT_FAILURE); -} diff --git a/src/cron.in b/src/cron.in new file mode 100644 index 0000000..97d49b4 --- /dev/null +++ b/src/cron.in @@ -0,0 +1,8 @@ +#!%GUILE% --no-auto-compile +-*- scheme -*- +!# + +(set! %load-path (cons "%modsrcdir%" %load-path)) +(set! %load-compiled-path (cons "%modbuilddir%" %load-compiled-path)) +(use-modules (mcron scripts cron)) +(main) diff --git a/src/crontab.c b/src/crontab.c deleted file mode 100644 index 16c0be6..0000000 --- a/src/crontab.c +++ /dev/null @@ -1,48 +0,0 @@ -/* crontab.c -- edit users' crontab files - Copyright © 2003, 2014 Dale Mellor - Copyright © 2015, 2016, 2017 Mathieu Lirzin - - This file is part of GNU Mcron. - - GNU Mcron is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - GNU Mcron is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNU Mcron. If not, see . */ - -#include "utils.h" - -/* Forward declarations. */ -static void inner_main (void *closure, int argc, char *argv[]); - -int -main (int argc, char *argv[]) -{ - /* Set Guile load paths to ensure that Mcron modules will be found after - installation. In a build environment let the 'pre-inst-env' script set - the correct paths. */ - if (getenv ("MCRON_UNINSTALLED") == NULL) - { - wrap_env_path ("GUILE_LOAD_PATH", PACKAGE_LOAD_PATH); - wrap_env_path ("GUILE_LOAD_COMPILED_PATH", PACKAGE_LOAD_COMPILED_PATH); - } - - scm_boot_guile (argc, argv, inner_main, NULL); - - return EXIT_SUCCESS; -} - -/* Launch the Mcron Guile main program. */ -static void -inner_main (void *closure, int argc, char *argv[]) -{ - scm_set_current_module (scm_c_resolve_module ("mcron scripts crontab")); - scm_call_0 (scm_variable_ref (scm_c_lookup ("main"))); -} diff --git a/src/crontab.in b/src/crontab.in new file mode 100644 index 0000000..fa31878 --- /dev/null +++ b/src/crontab.in @@ -0,0 +1,7 @@ +#!%GUILE% --no-auto-compile +-*- scheme -*- +!# + +(set! %load-path (cons "%modsrcdir%" %load-path)) +(set! %load-compiled-path (cons "%modbuilddir%" %load-compiled-path)) +((@ (mcron scripts crontab) main)) diff --git a/src/mcron.c b/src/mcron.c deleted file mode 100644 index c0b151a..0000000 --- a/src/mcron.c +++ /dev/null @@ -1,125 +0,0 @@ -/* mcron.c -- run jobs at scheduled times - Copyright © 2003, 2014 Dale Mellor - Copyright © 2015, 2016, 2017 Mathieu Lirzin - - This file is part of GNU Mcron. - - GNU Mcron is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - GNU Mcron is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNU Mcron. If not, see . */ - -#include "utils.h" -#include -#include - -/* Forward declarations. */ -static void inner_main (void *closure, int argc, char *argv[]); -static SCM parse_args (int argc, char *argv[]); -static error_t parse_opt (int key, char *arg, struct argp_state *state); - -int -main (int argc, char *argv[]) -{ - /* Set Guile load paths to ensure that Mcron modules will be found after - installation. In a build environment let the 'pre-inst-env' script set - the correct paths. */ - if (getenv ("MCRON_UNINSTALLED") == NULL) - { - wrap_env_path ("GUILE_LOAD_PATH", PACKAGE_LOAD_PATH); - wrap_env_path ("GUILE_LOAD_COMPILED_PATH", PACKAGE_LOAD_COMPILED_PATH); - } - - scm_boot_guile (argc, argv, inner_main, NULL); - - return EXIT_SUCCESS; -} - -/* Launch the Mcron Guile main program. */ -static void -inner_main (void *closure, int argc, char *argv[]) -{ - SCM config = parse_args (argc, argv); - scm_set_current_module (scm_c_resolve_module ("mcron scripts mcron")); - scm_call_1 (scm_variable_ref (scm_c_lookup ("main")), config); -} - -/* Handle command line arguments. */ -static SCM -parse_args (int argc, char *argv[]) -{ - static struct argp_option options[] = { - {"schedule", 's', "N", 0, - "Display the next N jobs that will be run"}, - {"daemon", 'd', 0, 0, - "Run as a daemon process"}, - {"stdin", 'i', "FORMAT", 0, - "Format of data passed as standard input or file arguments (default guile)"}, - {0, 0, 0, 0, 0} - }; - - static struct argp argp = { - .options = options, - .parser = parse_opt, - .args_doc = "[FILE...]", - .doc = "Run an mcron process according to the specifications in the " - "FILE... (`-' for standard input), or use all the files in " - "~/.config/cron (or the deprecated ~/.cron) with .guile or " - ".vixie extensions." - }; - - SCM config = SCM_EOL; - argp_program_version = PACKAGE_STRING; - argp_program_bug_address = PACKAGE_BUGREPORT; - argp_parse (&argp, argc, argv, 0, NULL, &config); - - return config; -} - -static error_t -parse_opt (int key, char *arg, struct argp_state *state) -{ - SCM *config = state->input; - - switch (key) - { - case 's': - assq_symbol_set_x (config, "schedule", - scm_from_int (atoi (arg))); - break; - case 'd': - assq_symbol_set_x (config, "daemon", SCM_BOOL_T); - break; - case 'i': - if (strncmp (arg, "vixie", 6) == 0) - assq_symbol_set_x (config, "vixie", SCM_BOOL_T); - break; - case ARGP_KEY_NO_ARGS: - assq_symbol_set_x (config, "files", SCM_EOL); - break; - case ARGP_KEY_ARGS: - { - SCM lst = SCM_EOL; - int filec = state->argc - state->next; - char **filev = state->argv + state->next; - - for (int i = filec - 1; i >= 0; i--) - lst = scm_cons (scm_from_locale_string (filev[i]), lst); - - assq_symbol_set_x (config, "files", lst); - break; - } - case ARGP_KEY_ARG: - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} diff --git a/src/mcron.in b/src/mcron.in new file mode 100644 index 0000000..4519ad0 --- /dev/null +++ b/src/mcron.in @@ -0,0 +1,8 @@ +#!%GUILE% --no-auto-compile +-*- scheme -*- +!# + +(set! %load-path (cons "%modsrcdir%" %load-path)) +(set! %load-compiled-path (cons "%modbuilddir%" %load-compiled-path)) +(use-modules (mcron scripts mcron)) +(main) diff --git a/src/mcron/base.scm b/src/mcron/base.scm index edcf1bc..f7b727d 100644 --- a/src/mcron/base.scm +++ b/src/mcron/base.scm @@ -139,7 +139,7 @@ entries that are to run at this time. When SCHEDULE is empty next time is (define* (display-schedule count #:optional (port (current-output-port)) #:key (schedule %global-schedule)) "Display on PORT a textual list of the next COUNT jobs to run. This -simulates the run of the job loop to display the resquested information. +simulates the run of the job loop to display the requested information. Since calling this procedure has the effect of mutating the job timings, the program must exit after. Otherwise the internal data state will be left unusable." diff --git a/src/mcron/job-specifier.scm b/src/mcron/job-specifier.scm index 120bf99..7eb2304 100644 --- a/src/mcron/job-specifier.scm +++ b/src/mcron/job-specifier.scm @@ -202,14 +202,14 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." ;; The job function, available to configuration files for adding a job rule to ;; the system. ;; -;; Here we must 'normalize' the next-time-function so that it is always a lambda -;; function which takes one argument (the last time the job ran) and returns a -;; single value (the next time the job should run). If the input value is a -;; string this is parsed as a Vixie-style time specification, and if it is a -;; list then we arrange to eval it (but note that such lists are expected to -;; ignore the function parameter - the last run time is always read from the -;; %CURRENT-ACTION-TIME parameter object). A similar normalization is applied to -;; the action. +;; Here we must 'normalize' the next-time-function so that it is always a +;; lambda function which takes one argument (the last time the job ran) and +;; returns a single value (the next time the job should run). If the input +;; value is a string this is parsed as a Vixie-style time specification, and +;; if it is a list then we arrange to eval it (but note that such lists are +;; expected to ignore the function parameter - the last run time is always +;; read from the %CURRENT-ACTION-TIME parameter object). A similar +;; normalization is applied to the action. ;; ;; Here we also compute the first time that the job is supposed to run, by ;; finding the next legitimate time from the current configuration time (set @@ -229,7 +229,8 @@ go into the list. For example, (range 1 6 2) returns '(1 3 5)." (cond ((procedure? time-proc) time-proc) ((string? time-proc) (parse-vixie-time time-proc)) ((list? time-proc) (lambda (current-time) - (primitive-eval time-proc))) + (eval time-proc + (resolve-module '(mcron job-specifier))))) (else (throw 'mcron-error 3 "job: invalid first argument (next-time-function; " diff --git a/src/mcron/scripts/cron.scm b/src/mcron/scripts/cron.scm index 1a97fdf..25c8a1a 100644 --- a/src/mcron/scripts/cron.scm +++ b/src/mcron/scripts/cron.scm @@ -17,6 +17,7 @@ ;;; You should have received a copy of the GNU General Public License ;;; along with GNU Mcron. If not, see . + (define-module (mcron scripts cron) #:use-module (ice-9 getopt-long) #:use-module (ice-9 ftw) @@ -28,6 +29,8 @@ #:use-module (srfi srfi-2) #:export (main)) + + (define (show-help) (display "Usage: cron [OPTIONS] Unless an option is specified, run a cron daemon as a detached process, @@ -41,12 +44,15 @@ reading all the information in the users' crontabs and in /etc/crontab. (newline) (show-package-information)) -(define %options - `((schedule (single-char #\s) (value #t) - (predicate ,(λ (str) (string->number str)))) - (noetc (single-char #\n) (value #f)) - (version (single-char #\v) (value #f)) - (help (single-char #\h) (value #f)))) + + +(define %options `((schedule (single-char #\s) (value #t) + (predicate ,string->number)) + (noetc (single-char #\n) (value #f)) + (version (single-char #\v) (value #f)) + (help (single-char #\h) (value #f)))) + + (define (delete-run-file) "Remove the /var/run/cron.pid file so that crontab and other invocations of @@ -60,6 +66,8 @@ received." noop) (quit)) + + (define (cron-file-descriptors) "Establish a socket to listen for updates from a crontab program, and return a list containing the file descriptors correponding to the files read by @@ -74,6 +82,8 @@ crontab. This requires that command-type is 'cron." (delete-file config-pid-file) (mcron-error 1 "Cannot bind to UNIX socket " config-socket-file)))) + + (define (process-files-in-system-directory) "Process all the files in the crontab directory. When the job procedure is run on behalf of the configuration files, the jobs are registered on the @@ -103,9 +113,6 @@ operation. The permissions on the /var/cron/tabs directory enforce this." (with-output-to-file config-pid-file noop)) ;; Clear MAILTO so that outputs are sent to the various users. (setenv "MAILTO" #f) - ;; XXX: At compile time, this yields a "possibly unbound variable" warning, - ;; but this is OK since it is bound in the C wrapper. - (c-set-cron-signals) ;; 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 @@ -138,42 +145,53 @@ option.\n") (let ((opts (getopt-long args %options))) (when config-debug (debug-enable 'backtrace)) - (cond - ((option-ref opts 'help #f) - (show-help) - (exit 0)) - ((option-ref opts 'version #f) - (show-version "cron") - (exit 0)) - ((not (zero? (getuid))) - (mcron-error 16 - "This program must be run by the root user (and should" - " have been installed as such).")) - ((access? config-pid-file F_OK) - (mcron-error 1 - "A cron daemon is already running.\n (If you are sure" - " this is not true, remove the file\n " - config-pid-file ".)")) - (else - (%process-files (option-ref opts 'schedule #f) - (option-ref opts 'noetc #f)) - (cond ((option-ref opts 'schedule #f) ;display jobs schedule - => (λ (count) - (display-schedule (max 1 (string->number count))) - (exit 0))) - (else (case (primitive-fork) ;run the daemon - ((0) - (setsid) - ;; we can now write the PID file. - (with-output-to-file config-pid-file - (λ () (display (getpid)) (newline)))) - (else (exit 0))))) - ;; Forever execute the 'run-job-loop', and when it drops out (can - ;; only be because a message has come in on the socket) we - ;; process the socket request before restarting the loop again. - (catch-mcron-error - (let ((fdes-list (cron-file-descriptors))) - (while #t - (run-job-loop fdes-list) - (unless (null? fdes-list) - (process-update-request fdes-list))))))))) + (cond ((option-ref opts 'help #f) + (show-help) + (exit 0)) + ((option-ref opts 'version #f) + (show-version "cron") + (exit 0)) + ((not (zero? (getuid))) + (mcron-error 16 + "This program must be run by the root user (and should" + " have been installed as such).")) + ((access? config-pid-file F_OK) + (mcron-error 1 + "A cron daemon is already running.\n (If you are sure" + " this is not true, remove the file\n " + config-pid-file ".)")) + (else + (%process-files (option-ref opts 'schedule #f) + (option-ref opts 'noetc #f)) + (cond ((option-ref opts 'schedule #f) + => (λ (count) + (display-schedule (max 1 (string->number count))) + (exit 0))))))) + + ;; Daemonize ourself. + (unless (eq? 0 (primitive-fork)) (exit 0)) + (setsid) + + ;; Set up process signal handlers, as signals are the only way to terminate + ;; the daemon and we MUST be graceful in defeat. + (for-each (λ (x) (sigaction x + (λ (sig) (catch #t + (λ () + (delete-file config-pid-file) + (delete-file config-socket-file)) + noop) + (exit EXIT_FAILURE)))) + '(SIGTERM SIGINT SIGQUIT SIGHUP)) + + ;; We can now write the PID file. + (with-output-to-file config-pid-file + (λ () (display (getpid)) (newline))) + + ;; Forever execute the 'run-job-loop', and when it drops out (can + ;; only be because a message has come in on the socket) we + ;; process the socket request before restarting the loop again. + (catch-mcron-error + (let ((fdes-list (cron-file-descriptors))) + (while #t + (run-job-loop fdes-list) + (unless (null? fdes-list) (process-update-request fdes-list)))))) diff --git a/src/mcron/scripts/crontab.scm b/src/mcron/scripts/crontab.scm index 902d3fc..480eadc 100644 --- a/src/mcron/scripts/crontab.scm +++ b/src/mcron/scripts/crontab.scm @@ -25,13 +25,13 @@ #:use-module (mcron vixie-specification) #:export (main)) -(define* (show-help) +(define (show-help) (display "Usage: crontab [-u user] file crontab [-u user] { -e | -l | -r } (default operation is replace, per 1003.2) -e (edit user's crontab) -l (list user's crontab) - -r (delete user's crontab") + -r (delete user's crontab)") (newline) (show-package-information)) diff --git a/src/mcron/scripts/mcron.scm b/src/mcron/scripts/mcron.scm index 8ae61cf..0da1cdf 100644 --- a/src/mcron/scripts/mcron.scm +++ b/src/mcron/scripts/mcron.scm @@ -19,14 +19,40 @@ (define-module (mcron scripts mcron) #:use-module (ice-9 ftw) + #:use-module (ice-9 getopt-long) + #:use-module (ice-9 local-eval) #:use-module (ice-9 rdelim) #:use-module (mcron base) #:use-module (mcron config) - #:use-module (mcron job-specifier) ;for user/system files + #:use-module (mcron job-specifier) ; For user/system files. #:use-module (mcron utils) #:use-module (mcron vixie-specification) #:export (main)) + + +(define (show-help) + (display "Usage: mcron [OPTION...] [FILE...] +Run an mcron process according to the specifications in the FILE... (`-' for +standard input), or use all the files in ~/.config/cron (or the deprecated +~/.cron) with .guile or .vixie extensions. + + -d, --daemon Run as a daemon process + -i, --stdin=(guile|vixie) Format of data passed as standard input or file + arguments (default guile) + -s, --schedule[=N] Display the next N (or 8) jobs that will be run + -?, --help Give this help list + -V, --version Print program version + +Mandatory or optional arguments to long options are also mandatory or optional +for any corresponding short options. + +Report bugs to bug-mcron@gnu.org. + +")) + + + (define process-user-file (let ((guile-regexp (make-regexp "\\.gui(le)?$")) (vixie-regexp (make-regexp "\\.vix(ie)?$"))) @@ -35,15 +61,17 @@ force guile syntax usage. If FILE-NAME format is not recognized, it is silently ignored." (cond ((string=? "-" file-name) - (if (string=? input "vixie") - (read-vixie-port (current-input-port)) + (if (string=? input "vixie") + (read-vixie-port (current-input-port)) (eval-string (read-string) (resolve-module '(mcron job-specifier))))) ((or guile-syntax? (regexp-exec guile-regexp file-name)) (eval-string (read-delimited "" (open-input-file file-name)) (resolve-module '(mcron job-specifier)))) ((regexp-exec vixie-regexp file-name) - (read-vixie-file file-name)))))) + (read-vixie-file file-name)))))) + + (define (process-files-in-user-directory input-type) "Process files in $XDG_CONFIG_HOME/cron and/or ~/.cron directories (if @@ -67,6 +95,8 @@ $XDG_CONFIG_HOME is not defined uses ~/.config/cron instead)." (mcron-error 13 "Cannot read files in your ~/.config/cron (or ~/.cron) directory.")))) + + (define (%process-files files input-type) (if (null? files) (process-files-in-user-directory input-type) @@ -77,30 +107,47 @@ $XDG_CONFIG_HOME is not defined uses ~/.config/cron instead)." ;;; Entry point. ;;; -(define* (main #:optional (opts '())) - (when config-debug - (debug-enable 'backtrace)) +(define (main) - (%process-files (or (assq-ref opts 'files) '()) - (if (assq-ref opts 'vixie) "vixie" "guile")) + (let ((options + (getopt-long + (command-line) + `((daemon (single-char #\d) (value #f)) + (stdin (single-char #\i) (value #t) + (predicate ,(λ (in) (or (string=? in "guile") + (string=? in "vixie"))))) + (schedule (single-char #\s) (value optional) + (predicate ,string->number)) + (help (single-char #\?)) + (version (single-char #\V)))))) - (cond ((assq-ref opts 'schedule) ;display jobs schedule - => (λ (count) - (display-schedule (max 1 count)) - (exit 0))) - ((assq-ref opts 'daemon) ;run mcron as a daemon - (case (primitive-fork) - ((0) (setsid)) - (else (exit 0))))) + (cond ((option-ref options 'help #f) (show-help) (exit 0)) + ((option-ref options 'version #f) (show-version "mcron") (exit 0))) + + (when config-debug + (debug-enable 'backtrace)) - ;; Forever execute the 'run-job-loop', and when it drops out (can - ;; only be because a message has come in on the socket) we process - ;; the socket request before restarting the loop again. - (catch-mcron-error - (let ((fdes-list '())) - (while #t - (run-job-loop fdes-list) - ;; we can also drop out of run-job-loop because of a SIGCHLD, - ;; so must test FDES-LIST. - (unless (null? fdes-list) - (process-update-request fdes-list)))))) + (%process-files (option-ref options '() '()) + (option-ref options 'stdin "guile")) + + (cond ((option-ref options 'schedule #f) + => (λ (count) + (let ((c (if (string? count) (string->number count) 8))) + (display-schedule (if (exact-integer? c) (max 1 c) 8))) + (exit 0))) + ((option-ref options 'daemon #f) + (case (primitive-fork) + ((0) (setsid)) + (else (exit 0))))) + + ;; Forever execute the 'run-job-loop', and when it drops out (can only be + ;; because a message has come in on the socket) we process the socket + ;; request before restarting the loop again. + (catch-mcron-error + (let ((fdes-list '())) + (while #t + (run-job-loop fdes-list) + ;; we can also drop out of run-job-loop because of a SIGCHLD, + ;; so must test FDES-LIST. + (unless (null? fdes-list) + (process-update-request fdes-list))))))) diff --git a/src/utils.c b/src/utils.c deleted file mode 100644 index 00a4150..0000000 --- a/src/utils.c +++ /dev/null @@ -1,48 +0,0 @@ -/* utils.c -- Utility functions. - Copyright © 2017 Mathieu Lirzin - - This file is part of GNU Mcron. - - GNU Mcron is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - GNU Mcron is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNU Mcron. If not, see . */ - -#include "utils.h" -#include -#include - -void -wrap_env_path (const char *envar, const char *dir) -{ - const char *path = getenv (envar); - if (path == NULL) - setenv (envar, dir, true); - else - { - char *new_path; - int ret = asprintf (&new_path, "%s:%s", dir, path); - if (ret >= 0) - setenv (envar, new_path, true); - else - { - perror (envar); - exit (EXIT_FAILURE); - } - free (new_path); - } -} - -void -assq_symbol_set_x (SCM *alst, const char *symbol, SCM val) -{ - *alst = scm_assq_set_x (*alst, scm_from_utf8_symbol (symbol), val); -} diff --git a/src/utils.h b/src/utils.h deleted file mode 100644 index 910483f..0000000 --- a/src/utils.h +++ /dev/null @@ -1,33 +0,0 @@ -/* utils.h -- Utility functions. - Copyright © 2017 Mathieu Lirzin - - This file is part of GNU Mcron. - - GNU Mcron is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - GNU Mcron is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNU Mcron. If not, see . */ - -#ifndef MCRON_UTILS_H -#define MCRON_UTILS_H - -#include - -/** - Append DIR in front of ENVAR environment variable value. If ENVAR is not - defined, then define it with DIR. Bail out if something went wrong. */ -extern void wrap_env_path (const char *envar, const char *dir); - -/** - In the association list pointed by ALST, set SYMBOL to VAL. */ -extern void assq_symbol_set_x (SCM *alst, const char *symbol, SCM val); - -#endif /* MCRON_UTILS_H */ diff --git a/tests/schedule-2.sh b/tests/schedule-2.sh index 7039123..531af54 100644 --- a/tests/schedule-2.sh +++ b/tests/schedule-2.sh @@ -26,13 +26,13 @@ export SOURCE_DATE_EPOCH TZ=UTC0 export TZ -LC_ALL=C -export LC_ALL - # Use current working directory to store mcron files XDG_CONFIG_HOME=`pwd` export XDG_CONFIG_HOME +LC_ALL=C +export LC_ALL + mkdir cron cat > cron/foo.guile < output-A -diff expected output-A \ +mcron -s cron/foo.guile > output +diff expected output \ || skip_ 'The -s option is not fully functional; -this will be fixed with a future version of GNU Guile and then -a future version of GNU Mcron.' +this will be fixed with a future version of GNU Guile.' Exit 0 From b596461e4229784f2a34992d183158c50e7d5192 Mon Sep 17 00:00:00 2001 From: atsb Date: Wed, 22 Apr 2020 20:42:17 +0200 Subject: [PATCH 225/239] push new NEWS file --- NEWS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/NEWS b/NEWS index f8d0d73..c5dc2b9 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,14 @@ GNU Mcron NEWS -*- outline -*- +* Noteworthy changes in release 1.2.0 (2020-04-22) [stable] + +** Improvements + C code removed, mcron becomes 100% Guile. + Make doc/mcron.texi gender neutral. + Have src/mcron/scripts/mcron.scm (process-user-file): use read and eval + instead of load. + New tests added for extra checks. + * Noteworthy changes in release 1.1.4 (2020-04-12) [stable] ** Improvements From 42fae5880eb53b48a2ea9bb4c8d07bbe23201ec9 Mon Sep 17 00:00:00 2001 From: atsb Date: Wed, 22 Apr 2020 20:45:35 +0200 Subject: [PATCH 226/239] prepare version 1.2.0 --- build-aux/guix.scm | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build-aux/guix.scm b/build-aux/guix.scm index 3c57bf1..25a281f 100644 --- a/build-aux/guix.scm +++ b/build-aux/guix.scm @@ -41,7 +41,7 @@ (package (inherit (specification->package "mcron")) - (version "1.1.4+") + (version "1.2.0") (source (local-file (dirname %srcdir) #:recursive? #t #:select? keep-mcron-file?)) (inputs diff --git a/configure.ac b/configure.ac index fb19229..f92619b 100755 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # along with GNU Mcron. If not, see . AC_PREREQ(2.61) -AC_INIT([GNU Mcron], [1.1.4+], [bug-mcron@gnu.org]) +AC_INIT([GNU Mcron], [1.2.0], [bug-mcron@gnu.org]) AC_CONFIG_SRCDIR([src/mcron/scripts/mcron.scm]) AC_CONFIG_AUX_DIR([build-aux]) AC_REQUIRE_AUX_FILE([test-driver.scm]) From b0151cad38a7f71b5888f393db9b7d2673b67b52 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Fri, 8 May 2020 17:19:28 +0200 Subject: [PATCH 227/239] build: Handle missing "bin" directory This fixes the generation of scripts when "bin" directory does not exist. * Makefile.am (bin/%): Invoke $(MKDIR_P) first. --- Makefile.am | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index e8fe80c..f63ff8f 100755 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. # Copyright © 2003 Dale Mellor -# Copyright © 2015, 2016, 2017, 2018 Mathieu Lirzin +# Copyright © 2015, 2016, 2017, 2018, 2020 Mathieu Lirzin # # This file is part of GNU Mcron. # @@ -100,7 +100,8 @@ DISTCLEANFILES = src/mcron/config.scm bin/% : src/%.in Makefile - -@sed -e 's,%PREFIX%,${prefix},g' \ + $(AM_V_GEN)$(MKDIR_P) bin ; \ + sed -e 's,%PREFIX%,${prefix},g' \ -e 's,%modsrcdir%,${guilesitedir},g' \ -e 's,%modbuilddir%,${guilesitegodir},g' \ -e 's,%localstatedir%,${localstatedir},g' \ @@ -112,8 +113,8 @@ bin/% : src/%.in Makefile -e 's,%PACKAGE_NAME%,@PACKAGE_NAME@,g' \ -e 's,%PACKAGE_URL%,@PACKAGE_URL@,g' \ -e 's,%GUILE%,$(GUILE),g' \ - $< > $@; - -@chmod a+x $@ + $< > $@ ; \ + chmod a+x $@ ## ------------ ## From 39857ae8442853e4f7d89116da400ca24d58ba7b Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Fri, 8 May 2020 17:20:06 +0200 Subject: [PATCH 228/239] build: Distribute script source files This allows 'make distcheck' to succeed. * Makefile.am (EXTRA_DIST): Add script source files. --- Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile.am b/Makefile.am index f63ff8f..b5c6260 100755 --- a/Makefile.am +++ b/Makefile.am @@ -148,6 +148,9 @@ EXTRA_DIST = \ bootstrap \ build-aux/guix.scm \ HACKING \ + src/cron.in \ + src/crontab.in \ + src/mcron.in \ tests/init.sh \ $(TESTS) From 9781507defd8ddd652653386eddbc5fc371e4742 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Fri, 8 May 2020 18:43:41 +0200 Subject: [PATCH 229/239] build: Handle missing "bin" directory This fixes the generation of scripts when "bin" directory does not exist. * Makefile.am (bin/%): Invoke $(MKDIR_P) first. --- Makefile.am | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index e8fe80c..f63ff8f 100755 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. # Copyright © 2003 Dale Mellor -# Copyright © 2015, 2016, 2017, 2018 Mathieu Lirzin +# Copyright © 2015, 2016, 2017, 2018, 2020 Mathieu Lirzin # # This file is part of GNU Mcron. # @@ -100,7 +100,8 @@ DISTCLEANFILES = src/mcron/config.scm bin/% : src/%.in Makefile - -@sed -e 's,%PREFIX%,${prefix},g' \ + $(AM_V_GEN)$(MKDIR_P) bin ; \ + sed -e 's,%PREFIX%,${prefix},g' \ -e 's,%modsrcdir%,${guilesitedir},g' \ -e 's,%modbuilddir%,${guilesitegodir},g' \ -e 's,%localstatedir%,${localstatedir},g' \ @@ -112,8 +113,8 @@ bin/% : src/%.in Makefile -e 's,%PACKAGE_NAME%,@PACKAGE_NAME@,g' \ -e 's,%PACKAGE_URL%,@PACKAGE_URL@,g' \ -e 's,%GUILE%,$(GUILE),g' \ - $< > $@; - -@chmod a+x $@ + $< > $@ ; \ + chmod a+x $@ ## ------------ ## From bc18db895064d9d0516b784ecac5270282c21d30 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Fri, 8 May 2020 18:43:42 +0200 Subject: [PATCH 230/239] build: Distribute script source files This allows 'make distcheck' to succeed. * Makefile.am (EXTRA_DIST): Add script source files. --- Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile.am b/Makefile.am index f63ff8f..b5c6260 100755 --- a/Makefile.am +++ b/Makefile.am @@ -148,6 +148,9 @@ EXTRA_DIST = \ bootstrap \ build-aux/guix.scm \ HACKING \ + src/cron.in \ + src/crontab.in \ + src/mcron.in \ tests/init.sh \ $(TESTS) From 6ae322468832759c1950779d6faff0fa550580ce Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Fri, 8 May 2020 18:06:20 +0200 Subject: [PATCH 231/239] scripts: Separate build/install directory context This prevents installed modules to interfere with the ones from the build directory. * src/cron.in: Augment Guile load paths with install directories only when MCRON_UNINSTALLED environment variable is not set. * src/crontab.in: Likewise. * src/mcron.in: Likewise. --- src/cron.in | 8 +++++--- src/crontab.in | 6 ++++-- src/mcron.in | 8 +++++--- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/cron.in b/src/cron.in index 97d49b4..25ad273 100644 --- a/src/cron.in +++ b/src/cron.in @@ -2,7 +2,9 @@ -*- scheme -*- !# -(set! %load-path (cons "%modsrcdir%" %load-path)) -(set! %load-compiled-path (cons "%modbuilddir%" %load-compiled-path)) -(use-modules (mcron scripts cron)) +(unless (getenv "MCRON_UNINSTALLED") + (set! %load-path (cons "%modsrcdir%" %load-path)) + (set! %load-compiled-path (cons "%modbuilddir%" %load-compiled-path))) + +(use-modules (mcron scripts cron)) (main) diff --git a/src/crontab.in b/src/crontab.in index fa31878..dad0dd2 100644 --- a/src/crontab.in +++ b/src/crontab.in @@ -2,6 +2,8 @@ -*- scheme -*- !# -(set! %load-path (cons "%modsrcdir%" %load-path)) -(set! %load-compiled-path (cons "%modbuilddir%" %load-compiled-path)) +(unless (getenv "MCRON_UNINSTALLED") + (set! %load-path (cons "%modsrcdir%" %load-path)) + (set! %load-compiled-path (cons "%modbuilddir%" %load-compiled-path))) + ((@ (mcron scripts crontab) main)) diff --git a/src/mcron.in b/src/mcron.in index 4519ad0..268743c 100644 --- a/src/mcron.in +++ b/src/mcron.in @@ -2,7 +2,9 @@ -*- scheme -*- !# -(set! %load-path (cons "%modsrcdir%" %load-path)) -(set! %load-compiled-path (cons "%modbuilddir%" %load-compiled-path)) -(use-modules (mcron scripts mcron)) +(unless (getenv "MCRON_UNINSTALLED") + (set! %load-path (cons "%modsrcdir%" %load-path)) + (set! %load-compiled-path (cons "%modbuilddir%" %load-compiled-path))) + +(use-modules (mcron scripts mcron)) (main) From bfe2a8921226cc7ccb54357d4f0c07534b763671 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Fri, 8 May 2020 19:24:00 +0200 Subject: [PATCH 232/239] build: Detect guile M4 macro expansion errors This ensures that the absence of 'pkg-config' or 'guile' M4 macros expansion do not pass the bootstrap step. * configure.ac: Allow or forbid some M4 macros patterns in the generated 'configure' script. --- configure.ac | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f92619b..d27e12e 100755 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ ## Process this file with autoconf to produce a configure script. # # Copyright © 2003, 2005, 2012, 2014 Dale Mellor -# Copyright © 2015, 2016, 2017, 2018 Mathieu Lirzin +# Copyright © 2015, 2016, 2017, 2018, 2020 Mathieu Lirzin # Copyright © 2018 宋文武 # # This file is part of GNU Mcron. @@ -33,6 +33,13 @@ AM_SILENT_RULES([yes]) # Enables silent rules by default. AC_CANONICAL_HOST +dnl We require pkg.m4 (from pkg-config) and guile.m4 (from Guile.) +dnl Make sure they are available when generating the configure script. +m4_pattern_forbid([^PKG_PROG]) +m4_pattern_forbid([^PKG_CHECK]) +m4_pattern_forbid([^GUILE_P]) +m4_pattern_allow([^GUILE_PKG_ERRORS]) + # Check for Guile development files. GUILE_PKG([3.0 2.2 2.0]) From 289e4c505e52402e5dfba08d57f2ba1d61a90bf3 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Sat, 9 May 2020 00:30:23 +0200 Subject: [PATCH 233/239] build: Remove C specific Guile configuration step * configure.ac: Remove unecessary PKG_CHECK_MODULES invocation. --- configure.ac | 5 ----- 1 file changed, 5 deletions(-) diff --git a/configure.ac b/configure.ac index d27e12e..97e9cff 100755 --- a/configure.ac +++ b/configure.ac @@ -43,12 +43,7 @@ m4_pattern_allow([^GUILE_PKG_ERRORS]) # Check for Guile development files. GUILE_PKG([3.0 2.2 2.0]) -# Set Guile flags without using GUILE_FLAGS which is requiring the unused -# 'config.rpath' script. -PKG_CHECK_MODULES(GUILE, [guile-$GUILE_EFFECTIVE_VERSION]) - # Checks for programs. - GUILE_PROGS AM_MISSING_PROG(HELP2MAN, help2man, $missing_dir) From 6a9bfcea4080390186be859c721e35f438d1272d Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Fri, 8 May 2020 20:43:50 +0100 Subject: [PATCH 234/239] Using new Guile command-line-processor. --- src/cron.in | 47 ++++++++++++- src/crontab.in | 38 ++++++++++- src/mcron.in | 50 +++++++++++++- src/mcron/scripts/cron.scm | 51 +++----------- src/mcron/scripts/crontab.scm | 121 +++++++++++++--------------------- src/mcron/scripts/mcron.scm | 66 ++++--------------- 6 files changed, 195 insertions(+), 178 deletions(-) diff --git a/src/cron.in b/src/cron.in index 25ad273..c22b701 100644 --- a/src/cron.in +++ b/src/cron.in @@ -2,9 +2,52 @@ -*- scheme -*- !# +;;;; cron -- run jobs at scheduled times +;;; Copyright © 2003, 2012, 2020 Dale Mellor +;;; Copyright © 2015, 2016, 2018 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . + + (unless (getenv "MCRON_UNINSTALLED") (set! %load-path (cons "%modsrcdir%" %load-path)) (set! %load-compiled-path (cons "%modbuilddir%" %load-compiled-path))) -(use-modules (mcron scripts cron)) -(main) +(use-modules (mcron scripts cron) + (ice-9 command-line-processor)) + +(process-command-line (command-line) + application "cron" + version "%VERSION%" + usage "[OPTIONS]" + help-preamble + "Unless an option is specified, run a cron daemon as a detached process," + "reading all the information in the usersʼ crontabs and in /etc/crontab." + option (--schedule=8 -s string->number + "display the next N (or 8) jobs that will be" + "run, and exit") + option (--noetc -n "do not check /etc/crontab for updates (use" + "of this option is HIGHLY RECOMMENDED)") + help-postamble + "Mandatory or optional arguments to long options are also mandatory or " + "optional for any corresponding short options." + bug-address "%PACKAGE_BUGREPORT%" + copyright + "2003, 2012, 2015, 2016, 2018, 2020 Free Software Foundation, Inc." + license GPLv3) + + +(main --schedule --noetc) diff --git a/src/crontab.in b/src/crontab.in index dad0dd2..f203a98 100644 --- a/src/crontab.in +++ b/src/crontab.in @@ -2,8 +2,44 @@ -*- scheme -*- !# +;;;; crontab -- run jobs at scheduled times +;;; Copyright © 2003, 2020 Dale Mellor +;;; Copyright © 2015, 2016, 2018 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . + + (unless (getenv "MCRON_UNINSTALLED") (set! %load-path (cons "%modsrcdir%" %load-path)) (set! %load-compiled-path (cons "%modbuilddir%" %load-compiled-path))) -((@ (mcron scripts crontab) main)) +(use-modules (mcron scripts crontab) + (ice-9 command-line-processor)) + +(process-command-line (command-line) + application "crontab" + version "%VERSION%" + usage "[-u user] { -e | -l | -r }" + help-preamble "the default operation is to replace, per 1003.2" + option (--user= -u "the user whose files are to be manipulated") + option (--edit -e "edit this userʼs crontab") + option (--list -l "list this userʼs crontab") + option (--remove -r "delete the userʼs crontab") + bug-address "%PACKAGE_BUGREPORT%" + copyright "2003, 2016, 2020 Free Software Foundation, Inc." + license GPLv3) + +((@ (mcron scripts crontab) main) --user --edit --list --remove --!) diff --git a/src/mcron.in b/src/mcron.in index 268743c..43dc326 100644 --- a/src/mcron.in +++ b/src/mcron.in @@ -2,9 +2,55 @@ -*- scheme -*- !# +;;;; mcron -- run jobs at scheduled times +;;; Copyright © 2003, 2012, 2020 Dale Mellor +;;; Copyright © 2015, 2016, 2018 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . + + (unless (getenv "MCRON_UNINSTALLED") (set! %load-path (cons "%modsrcdir%" %load-path)) (set! %load-compiled-path (cons "%modbuilddir%" %load-compiled-path))) -(use-modules (mcron scripts mcron)) -(main) +(use-modules (mcron scripts mcron) + (ice-9 command-line-processor)) + +(process-command-line (command-line) + application "mcron" + version "%VERSION%" + usage "[OPTIONS ...] [FILES ...]" + help-preamble + "Run unattended jobs according to instructions in the FILES... " + "(`-' for standard input), or use all the files in ~/.config/cron " + "(or the deprecated ~/.cron) with .guile or .vixie extensions.\n" + "Note that --daemon and --schedule are mutually exclusive." + option (--daemon -d "run as a daemon process") + option (--schedule=8 -s string->number + "display the next N (or 8) jobs that will be run," + "and then exit") + option (--stdin=guile short-i (λ (in) (or (string=? in "guile") + (string=? in "vixie"))) + "format of data passed as standard input or file " + "arguments, 'guile' or 'vixie' (default guile)") + help-postamble + "Mandatory or optional arguments to long options are also mandatory or " + "optional for any corresponding short options." + bug-address "%PACKAGE_BUGREPORT%" + copyright "2003, 2006, 2014, 2020 Free Software Foundation, Inc." + license GPLv3) + +(main --daemon --schedule --stdin --!) diff --git a/src/mcron/scripts/cron.scm b/src/mcron/scripts/cron.scm index 25c8a1a..b8463f6 100644 --- a/src/mcron/scripts/cron.scm +++ b/src/mcron/scripts/cron.scm @@ -19,7 +19,6 @@ (define-module (mcron scripts cron) - #:use-module (ice-9 getopt-long) #:use-module (ice-9 ftw) #:use-module (mcron base) #:use-module (mcron config) @@ -31,29 +30,6 @@ -(define (show-help) - (display "Usage: cron [OPTIONS] -Unless an option is specified, run a cron daemon as a detached process, -reading all the information in the users' crontabs and in /etc/crontab. - - -v, --version Display version - -h, --help Display this help message - -sN, --schedule[=]N Display the next N jobs that will be run by cron - -n, --noetc Do not check /etc/crontab for updates (HIGHLY - RECOMMENDED).") - (newline) - (show-package-information)) - - - -(define %options `((schedule (single-char #\s) (value #t) - (predicate ,string->number)) - (noetc (single-char #\n) (value #f)) - (version (single-char #\v) (value #f)) - (help (single-char #\h) (value #f)))) - - - (define (delete-run-file) "Remove the /var/run/cron.pid file so that crontab and other invocations of cron don't get the wrong idea that a daemon is currently running. This @@ -107,10 +83,7 @@ operation. The permissions on the /var/cron/tabs directory enforce this." (mcron-error 4 "You do not have permission to access the system crontabs.")))) -(define (%process-files schedule? noetc?) - ;; XXX: What is this supposed to do? - (when schedule? - (with-output-to-file config-pid-file noop)) +(define (%process-files noetc?) ;; Clear MAILTO so that outputs are sent to the various users. (setenv "MAILTO" #f) ;; Having defined all the necessary procedures for scanning various sets of @@ -141,17 +114,10 @@ option.\n") ;;; Entry point. ;;; -(define* (main #:optional (args (command-line))) - (let ((opts (getopt-long args %options))) - (when config-debug - (debug-enable 'backtrace)) - (cond ((option-ref opts 'help #f) - (show-help) - (exit 0)) - ((option-ref opts 'version #f) - (show-version "cron") - (exit 0)) - ((not (zero? (getuid))) +(define (main --schedule --noetc) + (when config-debug (debug-enable 'backtrace)) + + (cond ((not (zero? (getuid))) (mcron-error 16 "This program must be run by the root user (and should" " have been installed as such).")) @@ -161,12 +127,11 @@ option.\n") " this is not true, remove the file\n " config-pid-file ".)")) (else - (%process-files (option-ref opts 'schedule #f) - (option-ref opts 'noetc #f)) - (cond ((option-ref opts 'schedule #f) + (cond (--schedule => (λ (count) (display-schedule (max 1 (string->number count))) - (exit 0))))))) + (exit 0)))) + (%process-files --noetc))) ;; Daemonize ourself. (unless (eq? 0 (primitive-fork)) (exit 0)) diff --git a/src/mcron/scripts/crontab.scm b/src/mcron/scripts/crontab.scm index 480eadc..0c5c47f 100644 --- a/src/mcron/scripts/crontab.scm +++ b/src/mcron/scripts/crontab.scm @@ -1,5 +1,5 @@ ;;;; crontab -- edit user's cron tabs -;;; Copyright © 2003, 2004 Dale Mellor +;;; Copyright © 2003, 2004 Dale Mellor <> ;;; Copyright © 2016 Mathieu Lirzin ;;; ;;; This file is part of GNU Mcron. @@ -18,31 +18,12 @@ ;;; along with GNU Mcron. If not, see . (define-module (mcron scripts crontab) - #:use-module (ice-9 getopt-long) #:use-module (ice-9 rdelim) #:use-module (mcron config) #:use-module (mcron utils) #:use-module (mcron vixie-specification) #:export (main)) -(define (show-help) - (display "Usage: crontab [-u user] file - crontab [-u user] { -e | -l | -r } - (default operation is replace, per 1003.2) - -e (edit user's crontab) - -l (list user's crontab) - -r (delete user's crontab)") - (newline) - (show-package-information)) - -(define %options - '((user (single-char #\u) (value #t)) - (edit (single-char #\e) (value #f)) - (list (single-char #\l) (value #f)) - (remove (single-char #\r) (value #f)) - (version (single-char #\v) (value #f)) - (help (single-char #\h) (value #f)))) - (define (hit-server user-name) "Tell the running cron daemon that the user corresponding to USER-NAME has modified his crontab. USER-NAME is written to the @@ -56,6 +37,25 @@ USER-NAME has modified his crontab. USER-NAME is written to the (lambda (key . args) (display "Warning: a cron daemon is not running.\n")))) + + +;; Display the prompt and wait for user to type his choice. Return #t if the +;; answer begins with 'y' or 'Y', return #f if it begins with 'n' or 'N', +;; otherwise ask again. +(define (get-yes-no prompt . re-prompt) + (unless (null? re-prompt) + (display "Please answer y or n.\n")) + (display (string-append prompt " ")) + (let ((r (read-line))) + (if (not (string-null? r)) + (case (string-ref r 0) + ((#\y #\Y) #t) + ((#\n #\N) #f) + (else (get-yes-no prompt #t))) + (get-yes-no prompt #t)))) + + + (define (in-access-file? file name) "Scan FILE which should contain one user name per line (such as '/var/cron/allow' and '/var/cron/deny'). Return #t if NAME is in there, and @@ -78,60 +78,34 @@ USER-NAME has modified his crontab. USER-NAME is written to the ;;; Entry point. ;;; -(define* (main #:optional (args (command-line))) - (let ((opts (getopt-long args %options))) - (when config-debug - (debug-enable 'backtrace)) - (cond ((option-ref opts 'help #f) - (show-help) - (exit 0)) - ((option-ref opts 'version #f) - (show-version "crontab") - (exit 0))) - (let ((crontab-real-user - ;; This program should have been installed SUID root. Here we get - ;; the passwd entry for the real user who is running this program. - (passwd:name (getpw (getuid))))) +(define (main --user --edit --list --remove files) + (when config-debug (debug-enable 'backtrace)) + (let ((crontab-real-user + ;; This program should have been installed SUID root. Here we get + ;; the passwd entry for the real user who is running this program. + (passwd:name (getpw (getuid))))) - ;; If the real user is not allowed to use crontab due to the - ;; /var/cron/allow and/or /var/cron/deny files, bomb out now. - (if (or (eq? (in-access-file? config-allow-file crontab-real-user) #f) - (eq? (in-access-file? config-deny-file crontab-real-user) #t)) - (mcron-error 6 "Access denied by system operator.")) + ;; If the real user is not allowed to use crontab due to the + ;; /var/cron/allow and/or /var/cron/deny files, bomb out now. + (if (or (eq? (in-access-file? config-allow-file crontab-real-user) #f) + (eq? (in-access-file? config-deny-file crontab-real-user) #t)) + (mcron-error 6 "Access denied by system operator.")) - ;; Check that no more than one of the mutually exclusive options are - ;; being used. - (when (> (+ (if (option-ref opts 'edit #f) 1 0) - (if (option-ref opts 'list #f) 1 0) - (if (option-ref opts 'remove #f) 1 0)) - 1) + ;; Check that no more than one of the mutually exclusive options are + ;; being used. + (when (< 1 (+ (if --edit 1 0) (if --list 1 0) (if --remove 1 0))) (mcron-error 7 "Only one of options -e, -l or -r can be used.")) ;; Check that a non-root user is trying to read someone else's files. - (when (and (not (zero? (getuid))) - (option-ref opts 'user #f)) + (when (and (not (zero? (getuid))) --user) (mcron-error 8 "Only root can use the -u option.")) (letrec* (;; Iff the --user option is given, the crontab-user may be ;; different from the real user. - (crontab-user (option-ref opts 'user crontab-real-user)) + (crontab-user (or --user crontab-real-user)) ;; So now we know which crontab file we will be manipulating. - (crontab-file (string-append config-spool-dir "/" crontab-user)) - ;; Display the prompt and wait for user to type his - ;; choice. Return #t if the answer begins with 'y' or 'Y', - ;; return #f if it begins with 'n' or 'N', otherwise ask - ;; again. - (get-yes-no (λ (prompt . re-prompt) - (if (not (null? re-prompt)) - (display "Please answer y or n.\n")) - (display (string-append prompt " ")) - (let ((r (read-line))) - (if (not (string-null? r)) - (case (string-ref r 0) - ((#\y #\Y) #t) - ((#\n #\N) #f) - (else (get-yes-no prompt #t))) - (get-yes-no prompt #t)))))) + (crontab-file + (string-append config-spool-dir "/" crontab-user))) ;; There are four possible sub-personalities to the crontab ;; personality: list, remove, edit and replace (when the user uses no ;; options but supplies file names on the command line). @@ -140,7 +114,7 @@ USER-NAME has modified his crontab. USER-NAME is written to the ;; character-by-character to the standard output. If anything goes ;; wrong, it can only mean that this user does not have a crontab ;; file. - ((option-ref opts 'list #f) + (--list (catch #t (λ () (with-input-from-file crontab-file @@ -163,7 +137,7 @@ USER-NAME has modified his crontab. USER-NAME is written to the ;; cron daemon up, and remove the temporary file. If the parse fails, ;; we give user a choice of editing the file again or quitting the ;; program and losing all changes made. - ((option-ref opts 'edit #f) + (--edit (let ((temp-file (string-append config-tmp-dir "/crontab." (number->string (getpid))))) @@ -191,12 +165,9 @@ USER-NAME has modified his crontab. USER-NAME is written to the ;; In the remove personality we simply make an effort to delete the ;; crontab and wake the daemon. No worries if this fails. - ((option-ref opts 'remove #f) - (catch #t - (λ () - (delete-file crontab-file) - (hit-server crontab-user)) - noop)) + (--remove (catch #t (λ () (delete-file crontab-file) + (hit-server crontab-user)) + noop)) ;; XXX: This comment is wrong. ;; In the case of the replace personality we loop over all the @@ -206,8 +177,8 @@ USER-NAME has modified his crontab. USER-NAME is written to the ;; location; we deal with the standard input in the same way but ;; different. :-) In either case the server is woken so that it will ;; read the newly installed crontab. - ((not (null? (option-ref opts '() '()))) - (let ((input-file (car (option-ref opts '() '())))) + ((not (null? files)) + (let ((input-file (car files))) (catch-mcron-error (if (string=? input-file "-") (let ((input-string (read-string))) @@ -222,4 +193,4 @@ USER-NAME has modified his crontab. USER-NAME is written to the ;; The user is being silly. The message here is identical to the one ;; Vixie cron used to put out, for total compatibility. (else (mcron-error 15 - "usage error: file name must be specified for replace."))))))) + "usage error: file name must be specified for replace.")))))) diff --git a/src/mcron/scripts/mcron.scm b/src/mcron/scripts/mcron.scm index 0da1cdf..48efae5 100644 --- a/src/mcron/scripts/mcron.scm +++ b/src/mcron/scripts/mcron.scm @@ -1,6 +1,6 @@ ;;;; mcron -- run jobs at scheduled times -;;; Copyright © 2003, 2012 Dale Mellor -;;; Copyright © 2015, 2016, 2018 Mathieu Lirzin +;;; Copyright © 2003, 2012, 2020 Dale Mellor <> +;;; Copyright © 2015, 2016, 2018 Mathieu Lirzin ;;; ;;; This file is part of GNU Mcron. ;;; @@ -19,7 +19,6 @@ (define-module (mcron scripts mcron) #:use-module (ice-9 ftw) - #:use-module (ice-9 getopt-long) #:use-module (ice-9 local-eval) #:use-module (ice-9 rdelim) #:use-module (mcron base) @@ -31,28 +30,6 @@ -(define (show-help) - (display "Usage: mcron [OPTION...] [FILE...] -Run an mcron process according to the specifications in the FILE... (`-' for -standard input), or use all the files in ~/.config/cron (or the deprecated -~/.cron) with .guile or .vixie extensions. - - -d, --daemon Run as a daemon process - -i, --stdin=(guile|vixie) Format of data passed as standard input or file - arguments (default guile) - -s, --schedule[=N] Display the next N (or 8) jobs that will be run - -?, --help Give this help list - -V, --version Print program version - -Mandatory or optional arguments to long options are also mandatory or optional -for any corresponding short options. - -Report bugs to bug-mcron@gnu.org. - -")) - - - (define process-user-file (let ((guile-regexp (make-regexp "\\.gui(le)?$")) (vixie-regexp (make-regexp "\\.vix(ie)?$"))) @@ -107,38 +84,17 @@ $XDG_CONFIG_HOME is not defined uses ~/.config/cron instead)." ;;; Entry point. ;;; -(define (main) +(define (main --daemon --schedule --stdin file-list) - (let ((options - (getopt-long - (command-line) - `((daemon (single-char #\d) (value #f)) - (stdin (single-char #\i) (value #t) - (predicate ,(λ (in) (or (string=? in "guile") - (string=? in "vixie"))))) - (schedule (single-char #\s) (value optional) - (predicate ,string->number)) - (help (single-char #\?)) - (version (single-char #\V)))))) - - (cond ((option-ref options 'help #f) (show-help) (exit 0)) - ((option-ref options 'version #f) (show-version "mcron") (exit 0))) - - (when config-debug - (debug-enable 'backtrace)) - - (%process-files (option-ref options '() '()) - (option-ref options 'stdin "guile")) - - (cond ((option-ref options 'schedule #f) + (when config-debug (debug-enable 'backtrace)) + (%process-files file-list (or --stdin "guile")) + (cond (--schedule => (λ (count) - (let ((c (if (string? count) (string->number count) 8))) - (display-schedule (if (exact-integer? c) (max 1 c) 8))) + (display-schedule + (max 1 (inexact->exact (floor (string->number count))))) (exit 0))) - ((option-ref options 'daemon #f) - (case (primitive-fork) - ((0) (setsid)) - (else (exit 0))))) + (--daemon (case (primitive-fork) ((0) (setsid)) + (else (exit 0))))) ;; Forever execute the 'run-job-loop', and when it drops out (can only be ;; because a message has come in on the socket) we process the socket @@ -150,4 +106,4 @@ $XDG_CONFIG_HOME is not defined uses ~/.config/cron instead)." ;; we can also drop out of run-job-loop because of a SIGCHLD, ;; so must test FDES-LIST. (unless (null? fdes-list) - (process-update-request fdes-list))))))) + (process-update-request fdes-list)))))) From d2143dea3f3d933b4c7f19b738827d6ae2bcfe53 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 18 May 2020 12:54:50 +0200 Subject: [PATCH 235/239] vixie-time: Remove calls to 'pk' debugging facility * src/mcron/vixie-time.scm (parse-vixie-time): Remove pk usage --- src/mcron/vixie-time.scm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mcron/vixie-time.scm b/src/mcron/vixie-time.scm index 407ff60..0301434 100644 --- a/src/mcron/vixie-time.scm +++ b/src/mcron/vixie-time.scm @@ -1,6 +1,6 @@ ;;;; vixie-time.scm -- parse Vixie-style times ;;; Copyright © 2003 Dale Mellor -;;; Copyright © 2018 Mathieu Lirzin +;;; Copyright © 2018, 2020 Mathieu Lirzin ;;; ;;; This file is part of GNU Mcron. ;;; @@ -360,7 +360,7 @@ accounted for." (time-spec:list wday) (tm:mon time) (tm:year time))))) - (nudge-day! (pk time) (pk (cddr time-spec-list))) + (nudge-day! time (cddr time-spec-list)) (set-tm:hour time -1)) (unless (member (tm:hour time) (time-spec:list hour)) From 92a940cca55a07efb67c7588bbca99a9fe305025 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 18 May 2020 12:54:51 +0200 Subject: [PATCH 236/239] tests: Check (mcron vixie-specification) * tests/vixie-specification.scm: New file. * Makefile.am (TESTS): Register it. --- Makefile.am | 1 + tests/vixie-specification.scm | 144 ++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 tests/vixie-specification.scm diff --git a/Makefile.am b/Makefile.am index b5c6260..c7562c5 100755 --- a/Makefile.am +++ b/Makefile.am @@ -138,6 +138,7 @@ TESTS = \ tests/environment.scm \ tests/job-specifier.scm \ tests/utils.scm \ + tests/vixie-specification.scm \ tests/vixie-time.scm ## -------------- ## diff --git a/tests/vixie-specification.scm b/tests/vixie-specification.scm new file mode 100644 index 0000000..78c1dad --- /dev/null +++ b/tests/vixie-specification.scm @@ -0,0 +1,144 @@ +;;;; vixie-specification.scm -- tests for (mcron vixie-specificaion) module +;;; Copyright © 2020 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . + +(use-modules (srfi srfi-1) + (srfi srfi-64) + (mcron vixie-specification)) + +(setenv "TZ" "UTC0") + +;;; Do not send mail +(setenv "MAILTO" "") + +(define (create-file! content) + "Construct a temporary file port containing CONTENT which must be a string." + (let ((port (mkstemp! (string-copy "file-XXXXXX")))) + (display content port) + (force-output port) + port)) + +(define (clean-temp port) + "Close and Delete a temporary file port" + (let ((fname (port-filename port))) + (close port) + (delete-file fname))) + +(define schedule (@@ (mcron base) %global-schedule)) +(define schedule-user (@@ (mcron base) schedule-user)) +(define set-schedule-user! (@@ (mcron base) set-schedule-user!)) +(define job:environment (@@ (mcron base) job:environment)) +(define job:displayable (@@ (mcron base) job:displayable)) +(define job:user (@@ (mcron base) job:user)) + +(test-begin "vixie-specification") + +;;; Parse user crontab file + +(define user-crontab-example + "# Example crontab +FOO=x +BAR=y + +# Example of job definitions: +17 * * * * cd / && run baz +47 6 * * 7 foo -x /tmp/example || bar +") + +(define user-crontab (create-file! user-crontab-example)) + +(dynamic-wind + (const #t) + (lambda () + (set-schedule-user! schedule '()) + (read-vixie-file (port-filename user-crontab)) + + (test-assert "User schedule has exactly 2 matching jobs" + (lset= string=? + '("cd / && run baz" + "foo -x /tmp/example || bar") + (map job:displayable (schedule-user schedule)))) + + (test-assert "Job environment matches configuration" + (every (lambda (j) + (lset= equal? + '(("FOO" . "x") ("BAR" . "y")) + (job:environment j))) + (schedule-user schedule)))) + + (lambda () + (clean-temp user-crontab))) + +;;; Parse system crontab file + +;;; Get two existing users from the test environment. +(setpwent) +(define user0 (getpwent)) +(define user1 (or (getpwent) user0)) +(define system-crontab-example + (string-append + "# Example crontab +BAZ=z + +17 * * * * " (passwd:name user0) " cd / && run baz +47 6 * * 7 " (passwd:name user1) " foo -x /tmp/example || bar")) + +(define sys-crontab (create-file! system-crontab-example)) + +(dynamic-wind + (const #t) + (lambda () + (set-schedule-user! schedule '()) + (read-vixie-file (port-filename sys-crontab) parse-system-vixie-line) + + (test-assert "System schedule has exactly 2 matching jobs" + (lset= equal? + `((,user0 . "cd / && run baz") + (,user1 . "foo -x /tmp/example || bar")) + (map (lambda (j) + (cons (job:user j) (job:displayable j))) + (schedule-user schedule)))) + + (test-assert "Job environment matches configuration" + (every (lambda (j) + (lset= equal? '(("BAZ" . "z")) (job:environment j))) + (schedule-user schedule)))) + + (lambda () + (clean-temp sys-crontab))) + +;;; Try to parse a user crontab in a system context + +(define wrong-system-crontab-example + " +# Example of job definitions: +17 * * * * ls") + +(define wrong-sys-crontab (create-file! wrong-system-crontab-example)) + +(dynamic-wind + (const #t) + (lambda () + (test-error "missing user" + 'mcron-error + (read-vixie-file (port-filename wrong-sys-crontab) + parse-system-vixie-line))) + + (lambda () + (clean-temp wrong-sys-crontab))) + +(test-end) From 765bfbf4d9e4cd22371313f653cd6431034798f0 Mon Sep 17 00:00:00 2001 From: Mathieu Lirzin Date: Mon, 18 May 2020 12:54:52 +0200 Subject: [PATCH 237/239] tests: Check (mcron redirect) * tests/redirect.scm: New file. * Makefile.am (TESTS): Register it. * src/mcron/redirect.scm (with-mail-out): Adapt to facilitate testing. --- Makefile.am | 1 + src/mcron/redirect.scm | 12 ++++++---- tests/redirect.scm | 53 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 tests/redirect.scm diff --git a/Makefile.am b/Makefile.am index c7562c5..ddfad07 100755 --- a/Makefile.am +++ b/Makefile.am @@ -137,6 +137,7 @@ TESTS = \ tests/base.scm \ tests/environment.scm \ tests/job-specifier.scm \ + tests/redirect.scm \ tests/utils.scm \ tests/vixie-specification.scm \ tests/vixie-time.scm diff --git a/src/mcron/redirect.scm b/src/mcron/redirect.scm index b7df42c..8374552 100644 --- a/src/mcron/redirect.scm +++ b/src/mcron/redirect.scm @@ -1,5 +1,6 @@ ;;;; redirect.scm -- modify job outputs ;;; Copyright © 2003 Dale Mellor +;;; Copyright © 2020 Mathieu Lirzin ;;; Copyright © 2018 宋文武 ;;; ;;; This file is part of GNU Mcron. @@ -63,7 +64,10 @@ ;; the string, and output (including the error output) being sent to a pipe ;; opened on a mail transport. -(define (with-mail-out action . user) +(define* (with-mail-out action #:optional user #:key + (hostname (gethostname)) + (out (lambda () + (open-output-pipe config-sendmail)))) ;; Determine the name of the user who is to recieve the mail, looking for a ;; name in the optional user argument, then in the MAILTO environment @@ -72,7 +76,7 @@ (let* ((mailto (getenv "MAILTO")) (user (cond (mailto mailto) - ((not (null? user)) (car user)) + (user user) (else (getenv "LOGNAME")))) (parent->child (pipe)) (child->parent (pipe)) @@ -173,11 +177,11 @@ (open-output-file "/dev/null") ;; The sendmail command should read ;; recipients from the message header. - (open-output-pipe config-sendmail))) + (out))) (set-current-input-port (car child->parent)) (display "To: ") (display user) (newline) (display "From: mcron") (newline) - (display (string-append "Subject: " user "@" (gethostname))) + (display (string-append "Subject: " user "@" hostname)) (newline) (newline) diff --git a/tests/redirect.scm b/tests/redirect.scm new file mode 100644 index 0000000..700bfb4 --- /dev/null +++ b/tests/redirect.scm @@ -0,0 +1,53 @@ +;;;; redirect.scm -- tests for (mcron redirect) module +;;; Copyright © 2020 Mathieu Lirzin +;;; +;;; This file is part of GNU Mcron. +;;; +;;; GNU Mcron is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; GNU Mcron is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Mcron. If not, see . + +(use-modules (ice-9 textual-ports) + (srfi srfi-1) + (srfi srfi-64) + (mcron redirect)) + +(setenv "TZ" "UTC0") + +(test-begin "redirect") + +(define out (mkstemp! (string-copy "foo-XXXXXX"))) + +(dynamic-wind + (const #t) + (lambda () + (with-mail-out "echo 'foo'" "user0" + #:out (lambda () out) + #:hostname "localhost") + + (flush-all-ports) + + (test-equal "mail output" + "To: user0 +From: mcron +Subject: user0@localhost + +foo +" + (call-with-input-file (port-filename out) get-string-all))) + + (lambda () + (let ((fname (port-filename out))) + (close out) + (delete-file fname)))) + +(test-end) From 833ae20c31d9951e7721bb55441df2630aae4765 Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Mon, 8 Jun 2020 08:54:35 +0100 Subject: [PATCH 238/239] Version to 1.2.0+dmbcs. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 97e9cff..8948c9b 100755 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # along with GNU Mcron. If not, see . AC_PREREQ(2.61) -AC_INIT([GNU Mcron], [1.2.0], [bug-mcron@gnu.org]) +AC_INIT([GNU Mcron], [1.2.0+dmbcs], [bug-mcron@gnu.org]) AC_CONFIG_SRCDIR([src/mcron/scripts/mcron.scm]) AC_CONFIG_AUX_DIR([build-aux]) AC_REQUIRE_AUX_FILE([test-driver.scm]) From e7ed2cabcb36f8ba90bff6f90089ff22a02971bc Mon Sep 17 00:00:00 2001 From: Dale Mellor Date: Wed, 15 May 2024 13:23:58 +0100 Subject: [PATCH 239/239] =?UTF-8?q?Dale=20Mellor=CA=BCs=20key.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * dale.key: new file. --- dale.key | Bin 0 -> 2263 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 dale.key diff --git a/dale.key b/dale.key new file mode 100644 index 0000000000000000000000000000000000000000..3110d69fbe9646d7cf4cc9dddc1b9a84e38667d4 GIT binary patch literal 2263 zcma)-c{J4h9>;&Pn2dGC&XjFvEFrSRWSNkC4NaEJ$dYYDw);q>EZNHPBpKUKPu4WCf7x-@c;e37b3I&USl^`7Wfnq${jMlx;`I%&;;-#b+YEJ#+ZoLP&@0|c->>x> zP~I=V6{>q!BrIq)`Btw(6W>KWOMj&$Ag~*Wvx}K4#0*8|En8z1EFseAM?ajXB#yvF zb7}Tm0%V_D8^1LE8ORTjl-Y4x?aHGOgPry`#lenIs@17IY_nlm{CHhOwqj4WhS&I2 z{u_=JP-JDDf@@~|{*}cpC(({9`MaVKwpAJ^jWJxG0s7Q4vkz(1!XyR~kr7f!6O+7=xv#nrLBR?c{V(j)k|iJH0j_>clb zv6l}XIsun`{pCpk9$K-kP;Mj`K!Z^b7%QCl2m}n}1v5jSd|(I&EDQqk-(&(?yp%Em z3xWU^IHL2M$a@eW&geQB$U^N;Jon~%nVYd*XVq){LY`K;(F{ev07V>p0%HQ7Ym6fNoI|I?l_(0JamD>WwkpL?b-T36o?DJa#IF*marBRF zK#m7SF{~hX#=#P|*I!)p;FuK0vwN{FzhFg~z&}IxzmX4Fe|BFEd0c6(CzJ}tX!5r!? zIMd1V#%f|kRWKmO%OgA?LW6AJ9<<<6uizC8IzO!ZHw>Z=!PQ&Nlk}JTgdW&n0o3`# zpfgypFVPn3Ykwe3C;y!jCa{a}t?~mpreEP=;$?v|voi5Pz#!mX={oGFlI_3-m}ovtSyWe5T}j-R+9%*Uq18G^?!PFn=LD!&1^7Rr9mJ)C3&0?5-2=UI1a zMUF1`H&~cy2XC{uI+v?Goi)`Tk_m%Ua*K7I4vyCLn=TXYr3V$PtW_v{ zKTeQi$W%At4S1Z5gz?H1lab5n0X)i?Jy*LM>UrM4^WsSUaNNaWcQZ#QM&Ih($@-wl?mj&r`&x)vs5EE(!cS|C%+99eCq zn+hpX=!dm!<5MQmNul=>iZE|UgY`M%(>(wlcAJJ%QDxbq=a)5XSXNA4{@w0e`>GQm zU-YWgVBv3R4C|AZsEf@u(tAngtwK;-F$uFOp^$j;?emOM1rygu&(9(oAMoM5!TxFw zlFMWw!B^RWEp=|*53fM$B_iECSQdM}1$}cx3F_9XDemla!DpLl3_qj!=3XgL0t@%N zu=@l5n5&Q;d8Y+MKa@G6%~yDhW4X&6>t%~UKEzyD%oV>So2ZnDtBUHw)ls289Vo25#nx(k;Fi^dD+ksdonp_c~X+B=^lV42M=hTco z;-_0S8d_S@LwDxax-~AUY^sfgpWxd|x4m!sV`_s5A3?N(01y}gNW0CVxbK6bedXE^ zE|(~MrJAhLKGIK>^AzLUjX1iHyz~5V$l5&@TA{MTqc6FBj!#g{4)!l~`i!{C199U1 zJ5%h11DYxE#U?5Dh^{Sa<~hWqZ*-lCms`{$R;FEn85u{7vuc-4N_^Zc$d|5Z=Xp(p zszR1#T?#TXsgYyhOcxvYw;Ni2=lwEdn)HYlO|TAdn9pvGGi~Fbj}82Q!NRiw;EwZ& zYkJ6zU8SO913LKFZ=7Xoe%GI4P%G*-jmJ~=!=kcdf2&%HJ-)fn_jSD15-G)HX4u94-9IW)VMkM(3PKXWb)))_D9>&PxvY16mJgQl!BMT$9_Gq1V#0zDe zEe5s)vQc9x;Lb&GKxKXmUOiPZ&;N1BBh6h$wpvE(R*J6Wp5SWU5v6)#*E;VN=bj6l zo=-{NhMsZT4-+T*%+sj#>nT%fixqn7CkD*dd({Yy1>bL-c2Mitu77X13NKNoUy(i8 zvJGjIQIYtVsG#>p=b8TUdQj(!uRf_cQ%2LBu-wlp!LB+}mHoABX!Y-daer?2H>UFl zDaXl>MWDnWdYK2)-G^H>wlE4$^V67he~q4ITvLF}^;bI9O{tq}`i|udc2hF?bRGx! z-t{&iA(!1~ALitVARg1y$71qUO2iDwr2U27*e)l%^^#a4sKCLIf&V-XoMbSH?Qpe3 yeFAdM28BM_u9+K!IPw?X|LAMBROkESp!e>cH*jf5i literal 0 HcmV?d00001