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.
This commit is contained in:
Mathieu Lirzin 2015-08-16 10:33:37 +02:00
commit 3c903bfc80
7 changed files with 152 additions and 226 deletions

1
.gitignore vendored
View file

@ -27,7 +27,6 @@ install-sh
makefile
makefile.in
/mcron
mcron.c
/mdate-sh
*.o
missing

View file

@ -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)

View file

@ -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

View file

@ -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 <http://www.gnu.org/licenses/>.
#
#
#
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

102
mcron.c Normal file
View file

@ -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 <http://www.gnu.org/licenses/>. */
/* 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 <libguile.h>
#include <signal.h>
#include <string.h>
/* 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;
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
/*
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 <string.h>
#include <signal.h>
#include <libguile.h>
/* 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;
}

View file

@ -16,28 +16,22 @@
;; You should have received a copy of the GNU General Public License along
;; with GNU mcron. If not, see <http://www.gnu.org/licenses/>.
;;; 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 <http://gnu.org/licenses/gpl.html>\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 <http://gnu.org/licenses/gpl.html>
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: <http://www.gnu.org/gethelp/>\n"
config-package-bugreport
config-package-name
@ -135,34 +129,34 @@ General help using GNU software: <http://www.gnu.org/gethelp/>\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)