project: banish need for C compiler
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.
This commit is contained in:
parent
4a05a2e861
commit
1eedf3b6d2
17 changed files with 248 additions and 502 deletions
75
Makefile.am
75
Makefile.am
|
|
@ -21,40 +21,18 @@
|
||||||
## Programs. ##
|
## Programs. ##
|
||||||
## ---------- ##
|
## ---------- ##
|
||||||
|
|
||||||
bin_PROGRAMS = bin/mcron
|
bin_SCRIPTS = bin/mcron
|
||||||
|
noinst_SCRIPTS =
|
||||||
|
|
||||||
if MULTI_USER
|
if MULTI_USER
|
||||||
bin_PROGRAMS += bin/crontab
|
bin_SCRIPTS += bin/crontab
|
||||||
sbin_PROGRAMS = bin/cron
|
sbin_SCRIPTS = bin/cron
|
||||||
else
|
else
|
||||||
noinst_PROGRAMS = bin/cron bin/crontab
|
noinst_SCRIPTS += bin/cron bin/crontab
|
||||||
endif
|
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.
|
# wrapper to be used in the build environment and for running tests.
|
||||||
noinst_SCRIPTS = pre-inst-env
|
noinst_SCRIPTS += pre-inst-env
|
||||||
|
|
||||||
# local library.
|
|
||||||
noinst_LIBRARIES = src/libmcron.a
|
|
||||||
src_libmcron_a_SOURCES = \
|
|
||||||
src/utils.c \
|
|
||||||
src/utils.h
|
|
||||||
|
|
||||||
## --------------- ##
|
## --------------- ##
|
||||||
## Guile modules. ##
|
## Guile modules. ##
|
||||||
|
|
@ -97,7 +75,7 @@ compiled_modules = \
|
||||||
$(pkgmodulego_DATA) \
|
$(pkgmodulego_DATA) \
|
||||||
$(pkgscriptgo_DATA)
|
$(pkgscriptgo_DATA)
|
||||||
|
|
||||||
CLEANFILES = $(compiled_modules)
|
CLEANFILES = $(compiled_modules) bin/crontab bin/cron bin/mcron
|
||||||
DISTCLEANFILES = src/mcron/config.scm
|
DISTCLEANFILES = src/mcron/config.scm
|
||||||
|
|
||||||
# Unset 'GUILE_LOAD_COMPILED_PATH' altogether while compiling. Otherwise, if
|
# 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 \
|
--warn=format --warn=unbound-variable --warn=arity-mismatch \
|
||||||
--target="$(host)" --output="$@" "$<" $(devnull_verbose)
|
--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. ##
|
## Test suite. ##
|
||||||
## ------------ ##
|
## ------------ ##
|
||||||
|
|
@ -161,25 +157,28 @@ EXTRA_DIST = \
|
||||||
# Sed command for Transforming program names.
|
# Sed command for Transforming program names.
|
||||||
transform_exe = s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/
|
transform_exe = s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/
|
||||||
|
|
||||||
if MULTI_USER
|
|
||||||
install-exec-hook:
|
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}
|
chmod u+s $(DESTDIR)$(bindir)/$${tcrontab}
|
||||||
|
tcron=`echo cron | sed '$(transform_exe)'`; \
|
||||||
|
chmod u+s $(DESTDIR)$(sbindir)/$${tcron}
|
||||||
endif
|
endif
|
||||||
|
tmcron=`echo mcron | sed '$(transform_exe)'`;
|
||||||
|
|
||||||
installcheck-local:
|
installcheck-local:
|
||||||
## Check that only expected programs are installed and configured
|
## 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}
|
test -e $(DESTDIR)$(bindir)/$${tmcron}
|
||||||
if MULTI_USER
|
if MULTI_USER
|
||||||
tcrontab=`echo crontab$(EXEEXT) | sed '$(transform_exe)'`; \
|
tcrontab=`echo crontab | sed '$(transform_exe)'`; \
|
||||||
test -u $(DESTDIR)$(bindir)/$${tcrontab}
|
test -u $(DESTDIR)$(bindir)/$${tcrontab}
|
||||||
tcron=`echo cron$(EXEEXT) | sed '$(transform_exe)'`; \
|
tcron=`echo cron | sed '$(transform_exe)'`; \
|
||||||
test -e $(DESTDIR)$(sbindir)/$${tcron}
|
test -e $(DESTDIR)$(sbindir)/$${tcron}
|
||||||
else !MULTI_USER
|
else !MULTI_USER
|
||||||
tcrontab=`echo crontab$(EXEEXT) | sed '$(transform_exe)'`; \
|
tcrontab=`echo crontab | sed '$(transform_exe)'`; \
|
||||||
test ! -u $(DESTDIR)$(bindir)/$${tcrontab}
|
test ! -u $(DESTDIR)$(bindir)/$${tcrontab}
|
||||||
tcron=`echo cron$(EXEEXT) | sed '$(transform_exe)'`; \
|
tcron=`echo cron | sed '$(transform_exe)'`; \
|
||||||
test ! -f $(DESTDIR)$(sbindir)/$${tcron}
|
test ! -f $(DESTDIR)$(sbindir)/$${tcron}
|
||||||
endif !MULTI_USER
|
endif !MULTI_USER
|
||||||
|
|
||||||
|
|
@ -220,10 +219,10 @@ gen_man = \
|
||||||
esac
|
esac
|
||||||
|
|
||||||
$(srcdir)/doc/mcron.1: src/mcron/scripts/mcron.scm bin/mcron
|
$(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
|
$(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
|
$(srcdir)/doc/cron.8: src/mcron/scripts/cron.scm bin/cron
|
||||||
-@prog="cron"; man_section=8; $(gen_man)
|
-@prog="cron"; man_section=8; $(gen_man)
|
||||||
|
|
|
||||||
|
|
@ -32,16 +32,16 @@
|
||||||
'(".git" "autom4te" "Makefile.in" ".go" ".log"
|
'(".git" "autom4te" "Makefile.in" ".go" ".log"
|
||||||
"stamp-vti" ".dirstamp"))
|
"stamp-vti" ".dirstamp"))
|
||||||
(any (λ (str) (string-suffix? str file))
|
(any (λ (str) (string-suffix? str file))
|
||||||
'("trs""configure" "Makefile" "config.status" "pre-inst-env"
|
'("trs" "configure" "Makefile" "config.status" "pre-inst-env"
|
||||||
"aclocal.m4" "bin/cron" "bin/mcron" "bin/crontab" "config.cache"
|
"aclocal.m4" "bin/cron" "bin/mcron" "bin/crontab"
|
||||||
"guix.scm")))))
|
"config.cache" "guix.scm")))))
|
||||||
|
|
||||||
(define %srcdir
|
(define %srcdir
|
||||||
(or (current-source-directory) "."))
|
(or (current-source-directory) "."))
|
||||||
|
|
||||||
(package
|
(package
|
||||||
(inherit (specification->package "mcron"))
|
(inherit (specification->package "mcron"))
|
||||||
(version "1.1.4")
|
(version "1.1.4+")
|
||||||
(source (local-file (dirname %srcdir) #:recursive? #t
|
(source (local-file (dirname %srcdir) #:recursive? #t
|
||||||
#:select? keep-mcron-file?))
|
#:select? keep-mcron-file?))
|
||||||
(inputs
|
(inputs
|
||||||
|
|
|
||||||
55
configure.ac
55
configure.ac
|
|
@ -1,6 +1,6 @@
|
||||||
## Process this file with autoconf to produce a configure script.
|
## Process this file with autoconf to produce a configure script.
|
||||||
# Copyright © 2003, 2005, 2012, 2014 Dale Mellor
|
#
|
||||||
# <dale_mellor@users.sourceforge.net>
|
# Copyright © 2003, 2005, 2012, 2014 Dale Mellor <mcron-lsfnyl@rdmp.org>
|
||||||
# Copyright © 2015, 2016, 2017, 2018 Mathieu Lirzin <mthl@gnu.org>
|
# Copyright © 2015, 2016, 2017, 2018 Mathieu Lirzin <mthl@gnu.org>
|
||||||
# Copyright © 2018 宋文武 <iyzsong@member.fsf.org>
|
# Copyright © 2018 宋文武 <iyzsong@member.fsf.org>
|
||||||
#
|
#
|
||||||
|
|
@ -20,19 +20,18 @@
|
||||||
# along with GNU Mcron. If not, see <http://www.gnu.org/licenses/>.
|
# along with GNU Mcron. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
AC_PREREQ(2.61)
|
AC_PREREQ(2.61)
|
||||||
AC_INIT([GNU Mcron], [1.1.4], [bug-mcron@gnu.org])
|
AC_INIT([GNU Mcron], [1.1.4+], [bug-mcron@gnu.org])
|
||||||
AC_CONFIG_SRCDIR([src/mcron.c])
|
AC_CONFIG_SRCDIR([src/mcron/scripts/mcron.scm])
|
||||||
AC_CONFIG_AUX_DIR([build-aux])
|
AC_CONFIG_AUX_DIR([build-aux])
|
||||||
AC_REQUIRE_AUX_FILE([test-driver.scm])
|
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_CANONICAL_HOST
|
||||||
AC_PROG_AWK
|
|
||||||
AC_PROG_EGREP
|
|
||||||
AM_PROG_CC_C_O
|
|
||||||
AC_PROG_RANLIB
|
|
||||||
AM_PROG_AR
|
|
||||||
|
|
||||||
# Check for Guile development files.
|
# Check for Guile development files.
|
||||||
GUILE_PKG([3.0 2.2 2.0])
|
GUILE_PKG([3.0 2.2 2.0])
|
||||||
|
|
@ -41,12 +40,6 @@ GUILE_PKG([3.0 2.2 2.0])
|
||||||
# 'config.rpath' script.
|
# 'config.rpath' script.
|
||||||
PKG_CHECK_MODULES(GUILE, [guile-$GUILE_EFFECTIVE_VERSION])
|
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.
|
# Checks for programs.
|
||||||
|
|
||||||
GUILE_PROGS
|
GUILE_PROGS
|
||||||
|
|
@ -76,8 +69,8 @@ AC_MSG_CHECKING([which spool directory to use])
|
||||||
AC_ARG_WITH(spool-dir,
|
AC_ARG_WITH(spool-dir,
|
||||||
AC_HELP_STRING([--with-spool-dir],
|
AC_HELP_STRING([--with-spool-dir],
|
||||||
[the crontab spool directory (/var/cron/tabs)]),
|
[the crontab spool directory (/var/cron/tabs)]),
|
||||||
CONFIG_SPOOL_DIR=$withval,
|
CONFIG_SPOOL_DIR=$withval,
|
||||||
CONFIG_SPOOL_DIR=[/var/cron/tabs])
|
CONFIG_SPOOL_DIR=[/var/cron/tabs])
|
||||||
AC_MSG_RESULT($CONFIG_SPOOL_DIR)
|
AC_MSG_RESULT($CONFIG_SPOOL_DIR)
|
||||||
AC_SUBST(CONFIG_SPOOL_DIR)
|
AC_SUBST(CONFIG_SPOOL_DIR)
|
||||||
|
|
||||||
|
|
@ -85,8 +78,8 @@ AC_MSG_CHECKING([name of socket])
|
||||||
AC_ARG_WITH(socket-file,
|
AC_ARG_WITH(socket-file,
|
||||||
AC_HELP_STRING([--with-socket-file],
|
AC_HELP_STRING([--with-socket-file],
|
||||||
[unix pathname for cron socket (/var/cron/socket)]),
|
[unix pathname for cron socket (/var/cron/socket)]),
|
||||||
CONFIG_SOCKET_FILE=$withval,
|
CONFIG_SOCKET_FILE=$withval,
|
||||||
CONFIG_SOCKET_FILE=[/var/cron/socket])
|
CONFIG_SOCKET_FILE=[/var/cron/socket])
|
||||||
AC_MSG_RESULT($CONFIG_SOCKET_FILE)
|
AC_MSG_RESULT($CONFIG_SOCKET_FILE)
|
||||||
AC_SUBST(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_ARG_WITH(allow-file,
|
||||||
AC_HELP_STRING([--with-allow-file],
|
AC_HELP_STRING([--with-allow-file],
|
||||||
[the file of allowed users (/var/cron/allow)]),
|
[the file of allowed users (/var/cron/allow)]),
|
||||||
CONFIG_ALLOW_FILE=$withval,
|
CONFIG_ALLOW_FILE=$withval,
|
||||||
CONFIG_ALLOW_FILE=[/var/cron/allow])
|
CONFIG_ALLOW_FILE=[/var/cron/allow])
|
||||||
AC_MSG_RESULT($CONFIG_ALLOW_FILE)
|
AC_MSG_RESULT($CONFIG_ALLOW_FILE)
|
||||||
AC_SUBST(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_ARG_WITH(deny-file,
|
||||||
AC_HELP_STRING([--with-deny-file],
|
AC_HELP_STRING([--with-deny-file],
|
||||||
[the file of barred users (/var/cron/deny)]),
|
[the file of barred users (/var/cron/deny)]),
|
||||||
CONFIG_DENY_FILE=$withval,
|
CONFIG_DENY_FILE=$withval,
|
||||||
CONFIG_DENY_FILE=[/var/cron/deny])
|
CONFIG_DENY_FILE=[/var/cron/deny])
|
||||||
AC_MSG_RESULT($CONFIG_DENY_FILE)
|
AC_MSG_RESULT($CONFIG_DENY_FILE)
|
||||||
AC_SUBST(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_ARG_WITH(pid-file,
|
||||||
AC_HELP_STRING([--with-pid-file],
|
AC_HELP_STRING([--with-pid-file],
|
||||||
[the file to record cron's PID (/var/run/cron.pid)]),
|
[the file to record cron's PID (/var/run/cron.pid)]),
|
||||||
CONFIG_PID_FILE=$withval,
|
CONFIG_PID_FILE=$withval,
|
||||||
CONFIG_PID_FILE=[/var/run/cron.pid])
|
CONFIG_PID_FILE=[/var/run/cron.pid])
|
||||||
AC_MSG_RESULT($CONFIG_PID_FILE)
|
AC_MSG_RESULT($CONFIG_PID_FILE)
|
||||||
AC_SUBST(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_ARG_WITH(tmp-dir,
|
||||||
AC_HELP_STRING([--with-tmp-dir],
|
AC_HELP_STRING([--with-tmp-dir],
|
||||||
[directory to hold temporary files (/tmp)]),
|
[directory to hold temporary files (/tmp)]),
|
||||||
CONFIG_TMP_DIR=$withval,
|
CONFIG_TMP_DIR=$withval,
|
||||||
CONFIG_TMP_DIR=[/tmp])
|
CONFIG_TMP_DIR=[/tmp])
|
||||||
AC_MSG_RESULT($CONFIG_TMP_DIR)
|
AC_MSG_RESULT($CONFIG_TMP_DIR)
|
||||||
AC_SUBST(CONFIG_TMP_DIR)
|
AC_SUBST(CONFIG_TMP_DIR)
|
||||||
|
|
||||||
# Include the Maintainer's Makefile fragment, if it's here.
|
# Include the Maintainer's Makefile fragment, if it's here.
|
||||||
MAINT_MAKEFILE=/dev/null
|
MAINT_MAKEFILE=/dev/null
|
||||||
AS_IF([test -r "$srcdir/maint.mk"],
|
AS_IF([test -r "$srcdir/maint.mk"],
|
||||||
[MAINT_MAKEFILE="$srcdir/maint.mk"])
|
[MAINT_MAKEFILE="$srcdir/maint.mk"])
|
||||||
AC_SUBST_FILE([MAINT_MAKEFILE])
|
AC_SUBST_FILE([MAINT_MAKEFILE])
|
||||||
|
|
||||||
AC_CONFIG_FILES([pre-inst-env:build-aux/pre-inst-env.in],
|
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
|
AC_CONFIG_FILES([doc/config.texi
|
||||||
Makefile
|
Makefile
|
||||||
src/mcron/config.scm])
|
src/mcron/config.scm])
|
||||||
|
|
|
||||||
80
src/cron.c
80
src/cron.c
|
|
@ -1,80 +0,0 @@
|
||||||
/* cron.c -- run jobs at scheduled times
|
|
||||||
Copyright © 2003, 2014 Dale Mellor <dale_mellor@users.sourceforge.net>
|
|
||||||
Copyright © 2015, 2016, 2017 Mathieu Lirzin <mthl@gnu.org>
|
|
||||||
|
|
||||||
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 <http://www.gnu.org/licenses/>. */
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include <signal.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
8
src/cron.in
Normal file
8
src/cron.in
Normal file
|
|
@ -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)
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
/* crontab.c -- edit users' crontab files
|
|
||||||
Copyright © 2003, 2014 Dale Mellor <dale_mellor@users.sourceforge.net>
|
|
||||||
Copyright © 2015, 2016, 2017 Mathieu Lirzin <mthl@gnu.org>
|
|
||||||
|
|
||||||
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 <http://www.gnu.org/licenses/>. */
|
|
||||||
|
|
||||||
#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")));
|
|
||||||
}
|
|
||||||
7
src/crontab.in
Normal file
7
src/crontab.in
Normal file
|
|
@ -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))
|
||||||
125
src/mcron.c
125
src/mcron.c
|
|
@ -1,125 +0,0 @@
|
||||||
/* mcron.c -- run jobs at scheduled times
|
|
||||||
Copyright © 2003, 2014 Dale Mellor <dale_mellor@users.sourceforge.net>
|
|
||||||
Copyright © 2015, 2016, 2017 Mathieu Lirzin <mthl@gnu.org>
|
|
||||||
|
|
||||||
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 <http://www.gnu.org/licenses/>. */
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include <argp.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
8
src/mcron.in
Normal file
8
src/mcron.in
Normal file
|
|
@ -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)
|
||||||
|
|
@ -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))
|
(define* (display-schedule count #:optional (port (current-output-port))
|
||||||
#:key (schedule %global-schedule))
|
#:key (schedule %global-schedule))
|
||||||
"Display on PORT a textual list of the next COUNT jobs to run. This
|
"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
|
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
|
program must exit after. Otherwise the internal data state will be left
|
||||||
unusable."
|
unusable."
|
||||||
|
|
|
||||||
|
|
@ -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 job function, available to configuration files for adding a job rule to
|
||||||
;; the system.
|
;; the system.
|
||||||
;;
|
;;
|
||||||
;; Here we must 'normalize' the next-time-function so that it is always a lambda
|
;; Here we must 'normalize' the next-time-function so that it is always a
|
||||||
;; function which takes one argument (the last time the job ran) and returns a
|
;; lambda function which takes one argument (the last time the job ran) and
|
||||||
;; single value (the next time the job should run). If the input value is a
|
;; returns a single value (the next time the job should run). If the input
|
||||||
;; string this is parsed as a Vixie-style time specification, and if it is a
|
;; value is a string this is parsed as a Vixie-style time specification, and
|
||||||
;; list then we arrange to eval it (but note that such lists are expected to
|
;; if it is a list then we arrange to eval it (but note that such lists are
|
||||||
;; ignore the function parameter - the last run time is always read from the
|
;; expected to ignore the function parameter - the last run time is always
|
||||||
;; %CURRENT-ACTION-TIME parameter object). A similar normalization is applied to
|
;; read from the %CURRENT-ACTION-TIME parameter object). A similar
|
||||||
;; the action.
|
;; normalization is applied to the action.
|
||||||
;;
|
;;
|
||||||
;; Here we also compute the first time that the job is supposed to run, by
|
;; 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
|
;; 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)
|
(cond ((procedure? time-proc) time-proc)
|
||||||
((string? time-proc) (parse-vixie-time time-proc))
|
((string? time-proc) (parse-vixie-time time-proc))
|
||||||
((list? time-proc) (lambda (current-time)
|
((list? time-proc) (lambda (current-time)
|
||||||
(primitive-eval time-proc)))
|
(eval time-proc
|
||||||
|
(resolve-module '(mcron job-specifier)))))
|
||||||
(else
|
(else
|
||||||
(throw 'mcron-error 3
|
(throw 'mcron-error 3
|
||||||
"job: invalid first argument (next-time-function; "
|
"job: invalid first argument (next-time-function; "
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
;;; You should have received a copy of the GNU General Public License
|
;;; You should have received a copy of the GNU General Public License
|
||||||
;;; along with GNU Mcron. If not, see <http://www.gnu.org/licenses/>.
|
;;; along with GNU Mcron. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
(define-module (mcron scripts cron)
|
(define-module (mcron scripts cron)
|
||||||
#:use-module (ice-9 getopt-long)
|
#:use-module (ice-9 getopt-long)
|
||||||
#:use-module (ice-9 ftw)
|
#:use-module (ice-9 ftw)
|
||||||
|
|
@ -28,6 +29,8 @@
|
||||||
#:use-module (srfi srfi-2)
|
#:use-module (srfi srfi-2)
|
||||||
#:export (main))
|
#:export (main))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(define (show-help)
|
(define (show-help)
|
||||||
(display "Usage: cron [OPTIONS]
|
(display "Usage: cron [OPTIONS]
|
||||||
Unless an option is specified, run a cron daemon as a detached process,
|
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)
|
(newline)
|
||||||
(show-package-information))
|
(show-package-information))
|
||||||
|
|
||||||
(define %options
|
|
||||||
`((schedule (single-char #\s) (value #t)
|
|
||||||
(predicate ,(λ (str) (string->number str))))
|
(define %options `((schedule (single-char #\s) (value #t)
|
||||||
(noetc (single-char #\n) (value #f))
|
(predicate ,string->number))
|
||||||
(version (single-char #\v) (value #f))
|
(noetc (single-char #\n) (value #f))
|
||||||
(help (single-char #\h) (value #f))))
|
(version (single-char #\v) (value #f))
|
||||||
|
(help (single-char #\h) (value #f))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(define (delete-run-file)
|
(define (delete-run-file)
|
||||||
"Remove the /var/run/cron.pid file so that crontab and other invocations of
|
"Remove the /var/run/cron.pid file so that crontab and other invocations of
|
||||||
|
|
@ -60,6 +66,8 @@ received."
|
||||||
noop)
|
noop)
|
||||||
(quit))
|
(quit))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(define (cron-file-descriptors)
|
(define (cron-file-descriptors)
|
||||||
"Establish a socket to listen for updates from a crontab program, and return
|
"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
|
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)
|
(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-files-in-system-directory)
|
(define (process-files-in-system-directory)
|
||||||
"Process all the files in the crontab directory. When the job procedure is
|
"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
|
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))
|
(with-output-to-file config-pid-file noop))
|
||||||
;; Clear MAILTO so that outputs are sent to the various users.
|
;; Clear MAILTO so that outputs are sent to the various users.
|
||||||
(setenv "MAILTO" #f)
|
(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
|
;; Having defined all the necessary procedures for scanning various sets of
|
||||||
;; files, we perform the actual configuration of the program depending on
|
;; 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
|
;; 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)))
|
(let ((opts (getopt-long args %options)))
|
||||||
(when config-debug
|
(when config-debug
|
||||||
(debug-enable 'backtrace))
|
(debug-enable 'backtrace))
|
||||||
(cond
|
(cond ((option-ref opts 'help #f)
|
||||||
((option-ref opts 'help #f)
|
(show-help)
|
||||||
(show-help)
|
(exit 0))
|
||||||
(exit 0))
|
((option-ref opts 'version #f)
|
||||||
((option-ref opts 'version #f)
|
(show-version "cron")
|
||||||
(show-version "cron")
|
(exit 0))
|
||||||
(exit 0))
|
((not (zero? (getuid)))
|
||||||
((not (zero? (getuid)))
|
(mcron-error 16
|
||||||
(mcron-error 16
|
"This program must be run by the root user (and should"
|
||||||
"This program must be run by the root user (and should"
|
" have been installed as such)."))
|
||||||
" have been installed as such)."))
|
((access? config-pid-file F_OK)
|
||||||
((access? config-pid-file F_OK)
|
(mcron-error 1
|
||||||
(mcron-error 1
|
"A cron daemon is already running.\n (If you are sure"
|
||||||
"A cron daemon is already running.\n (If you are sure"
|
" this is not true, remove the file\n "
|
||||||
" this is not true, remove the file\n "
|
config-pid-file ".)"))
|
||||||
config-pid-file ".)"))
|
(else
|
||||||
(else
|
(%process-files (option-ref opts 'schedule #f)
|
||||||
(%process-files (option-ref opts 'schedule #f)
|
(option-ref opts 'noetc #f))
|
||||||
(option-ref opts 'noetc #f))
|
(cond ((option-ref opts 'schedule #f)
|
||||||
(cond ((option-ref opts 'schedule #f) ;display jobs schedule
|
=> (λ (count)
|
||||||
=> (λ (count)
|
(display-schedule (max 1 (string->number count)))
|
||||||
(display-schedule (max 1 (string->number count)))
|
(exit 0)))))))
|
||||||
(exit 0)))
|
|
||||||
(else (case (primitive-fork) ;run the daemon
|
;; Daemonize ourself.
|
||||||
((0)
|
(unless (eq? 0 (primitive-fork)) (exit 0))
|
||||||
(setsid)
|
(setsid)
|
||||||
;; we can now write the PID file.
|
|
||||||
(with-output-to-file config-pid-file
|
;; Set up process signal handlers, as signals are the only way to terminate
|
||||||
(λ () (display (getpid)) (newline))))
|
;; the daemon and we MUST be graceful in defeat.
|
||||||
(else (exit 0)))))
|
(for-each (λ (x) (sigaction x
|
||||||
;; Forever execute the 'run-job-loop', and when it drops out (can
|
(λ (sig) (catch #t
|
||||||
;; only be because a message has come in on the socket) we
|
(λ ()
|
||||||
;; process the socket request before restarting the loop again.
|
(delete-file config-pid-file)
|
||||||
(catch-mcron-error
|
(delete-file config-socket-file))
|
||||||
(let ((fdes-list (cron-file-descriptors)))
|
noop)
|
||||||
(while #t
|
(exit EXIT_FAILURE))))
|
||||||
(run-job-loop fdes-list)
|
'(SIGTERM SIGINT SIGQUIT SIGHUP))
|
||||||
(unless (null? fdes-list)
|
|
||||||
(process-update-request fdes-list)))))))))
|
;; 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))))))
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,13 @@
|
||||||
#:use-module (mcron vixie-specification)
|
#:use-module (mcron vixie-specification)
|
||||||
#:export (main))
|
#:export (main))
|
||||||
|
|
||||||
(define* (show-help)
|
(define (show-help)
|
||||||
(display "Usage: crontab [-u user] file
|
(display "Usage: crontab [-u user] file
|
||||||
crontab [-u user] { -e | -l | -r }
|
crontab [-u user] { -e | -l | -r }
|
||||||
(default operation is replace, per 1003.2)
|
(default operation is replace, per 1003.2)
|
||||||
-e (edit user's crontab)
|
-e (edit user's crontab)
|
||||||
-l (list user's crontab)
|
-l (list user's crontab)
|
||||||
-r (delete user's crontab")
|
-r (delete user's crontab)")
|
||||||
(newline)
|
(newline)
|
||||||
(show-package-information))
|
(show-package-information))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,40 @@
|
||||||
|
|
||||||
(define-module (mcron scripts mcron)
|
(define-module (mcron scripts mcron)
|
||||||
#:use-module (ice-9 ftw)
|
#:use-module (ice-9 ftw)
|
||||||
|
#:use-module (ice-9 getopt-long)
|
||||||
|
#:use-module (ice-9 local-eval)
|
||||||
#:use-module (ice-9 rdelim)
|
#:use-module (ice-9 rdelim)
|
||||||
#:use-module (mcron base)
|
#:use-module (mcron base)
|
||||||
#:use-module (mcron config)
|
#: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 utils)
|
||||||
#:use-module (mcron vixie-specification)
|
#:use-module (mcron vixie-specification)
|
||||||
#:export (main))
|
#: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
|
(define process-user-file
|
||||||
(let ((guile-regexp (make-regexp "\\.gui(le)?$"))
|
(let ((guile-regexp (make-regexp "\\.gui(le)?$"))
|
||||||
(vixie-regexp (make-regexp "\\.vix(ie)?$")))
|
(vixie-regexp (make-regexp "\\.vix(ie)?$")))
|
||||||
|
|
@ -35,15 +61,17 @@
|
||||||
force guile syntax usage. If FILE-NAME format is not recognized, it is
|
force guile syntax usage. If FILE-NAME format is not recognized, it is
|
||||||
silently ignored."
|
silently ignored."
|
||||||
(cond ((string=? "-" file-name)
|
(cond ((string=? "-" file-name)
|
||||||
(if (string=? input "vixie")
|
(if (string=? input "vixie")
|
||||||
(read-vixie-port (current-input-port))
|
(read-vixie-port (current-input-port))
|
||||||
(eval-string (read-string)
|
(eval-string (read-string)
|
||||||
(resolve-module '(mcron job-specifier)))))
|
(resolve-module '(mcron job-specifier)))))
|
||||||
((or guile-syntax? (regexp-exec guile-regexp file-name))
|
((or guile-syntax? (regexp-exec guile-regexp file-name))
|
||||||
(eval-string (read-delimited "" (open-input-file file-name))
|
(eval-string (read-delimited "" (open-input-file file-name))
|
||||||
(resolve-module '(mcron job-specifier))))
|
(resolve-module '(mcron job-specifier))))
|
||||||
((regexp-exec vixie-regexp file-name)
|
((regexp-exec vixie-regexp file-name)
|
||||||
(read-vixie-file file-name))))))
|
(read-vixie-file file-name))))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(define (process-files-in-user-directory input-type)
|
(define (process-files-in-user-directory input-type)
|
||||||
"Process files in $XDG_CONFIG_HOME/cron and/or ~/.cron directories (if
|
"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
|
(mcron-error 13
|
||||||
"Cannot read files in your ~/.config/cron (or ~/.cron) directory."))))
|
"Cannot read files in your ~/.config/cron (or ~/.cron) directory."))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(define (%process-files files input-type)
|
(define (%process-files files input-type)
|
||||||
(if (null? files)
|
(if (null? files)
|
||||||
(process-files-in-user-directory input-type)
|
(process-files-in-user-directory input-type)
|
||||||
|
|
@ -77,30 +107,47 @@ $XDG_CONFIG_HOME is not defined uses ~/.config/cron instead)."
|
||||||
;;; Entry point.
|
;;; Entry point.
|
||||||
;;;
|
;;;
|
||||||
|
|
||||||
(define* (main #:optional (opts '()))
|
(define (main)
|
||||||
(when config-debug
|
|
||||||
(debug-enable 'backtrace))
|
|
||||||
|
|
||||||
(%process-files (or (assq-ref opts 'files) '())
|
(let ((options
|
||||||
(if (assq-ref opts 'vixie) "vixie" "guile"))
|
(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
|
(cond ((option-ref options 'help #f) (show-help) (exit 0))
|
||||||
=> (λ (count)
|
((option-ref options 'version #f) (show-version "mcron") (exit 0)))
|
||||||
(display-schedule (max 1 count))
|
|
||||||
(exit 0)))
|
(when config-debug
|
||||||
((assq-ref opts 'daemon) ;run mcron as a daemon
|
(debug-enable 'backtrace))
|
||||||
(case (primitive-fork)
|
|
||||||
((0) (setsid))
|
|
||||||
(else (exit 0)))))
|
|
||||||
|
|
||||||
;; Forever execute the 'run-job-loop', and when it drops out (can
|
(%process-files (option-ref options '() '())
|
||||||
;; only be because a message has come in on the socket) we process
|
(option-ref options 'stdin "guile"))
|
||||||
;; the socket request before restarting the loop again.
|
|
||||||
(catch-mcron-error
|
(cond ((option-ref options 'schedule #f)
|
||||||
(let ((fdes-list '()))
|
=> (λ (count)
|
||||||
(while #t
|
(let ((c (if (string? count) (string->number count) 8)))
|
||||||
(run-job-loop fdes-list)
|
(display-schedule (if (exact-integer? c) (max 1 c) 8)))
|
||||||
;; we can also drop out of run-job-loop because of a SIGCHLD,
|
(exit 0)))
|
||||||
;; so must test FDES-LIST.
|
((option-ref options 'daemon #f)
|
||||||
(unless (null? fdes-list)
|
(case (primitive-fork)
|
||||||
(process-update-request fdes-list))))))
|
((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)))))))
|
||||||
|
|
|
||||||
48
src/utils.c
48
src/utils.c
|
|
@ -1,48 +0,0 @@
|
||||||
/* utils.c -- Utility functions.
|
|
||||||
Copyright © 2017 Mathieu Lirzin <mthl@gnu.org>
|
|
||||||
|
|
||||||
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 <http://www.gnu.org/licenses/>. */
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
33
src/utils.h
33
src/utils.h
|
|
@ -1,33 +0,0 @@
|
||||||
/* utils.h -- Utility functions.
|
|
||||||
Copyright © 2017 Mathieu Lirzin <mthl@gnu.org>
|
|
||||||
|
|
||||||
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 <http://www.gnu.org/licenses/>. */
|
|
||||||
|
|
||||||
#ifndef MCRON_UTILS_H
|
|
||||||
#define MCRON_UTILS_H
|
|
||||||
|
|
||||||
#include <libguile.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);
|
|
||||||
|
|
||||||
/**
|
|
||||||
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 */
|
|
||||||
|
|
@ -26,13 +26,13 @@ export SOURCE_DATE_EPOCH
|
||||||
TZ=UTC0
|
TZ=UTC0
|
||||||
export TZ
|
export TZ
|
||||||
|
|
||||||
LC_ALL=C
|
|
||||||
export LC_ALL
|
|
||||||
|
|
||||||
# Use current working directory to store mcron files
|
# Use current working directory to store mcron files
|
||||||
XDG_CONFIG_HOME=`pwd`
|
XDG_CONFIG_HOME=`pwd`
|
||||||
export XDG_CONFIG_HOME
|
export XDG_CONFIG_HOME
|
||||||
|
|
||||||
|
LC_ALL=C
|
||||||
|
export LC_ALL
|
||||||
|
|
||||||
mkdir cron
|
mkdir cron
|
||||||
cat > cron/foo.guile <<EOF
|
cat > cron/foo.guile <<EOF
|
||||||
(job '(next-second) '(display "foo\n"))
|
(job '(next-second) '(display "foo\n"))
|
||||||
|
|
@ -73,10 +73,9 @@ Thu Jan 1 00:00:08 1970 +0000
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
mcron -s cron/foo.guile > output-A
|
mcron -s cron/foo.guile > output
|
||||||
diff expected output-A \
|
diff expected output \
|
||||||
|| skip_ 'The -s option is not fully functional;
|
|| skip_ 'The -s option is not fully functional;
|
||||||
this will be fixed with a future version of GNU Guile and then
|
this will be fixed with a future version of GNU Guile.'
|
||||||
a future version of GNU Mcron.'
|
|
||||||
|
|
||||||
Exit 0
|
Exit 0
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue