diff options
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | README.md | 7 | ||||
-rw-r--r-- | cmd/Makemodule.am | 5 | ||||
-rw-r--r-- | cmd/service/schedule.c | 90 | ||||
-rw-r--r-- | cmd/service/service.8 | 10 | ||||
-rw-r--r-- | cmd/service/unschedule.c | 82 | ||||
-rw-r--r-- | configure.ac | 12 | ||||
-rw-r--r-- | crond/Makemodule.am | 11 | ||||
-rw-r--r-- | crond/cronscan.c | 77 | ||||
-rw-r--r-- | crond/crontab.c | 50 | ||||
-rw-r--r-- | crond/crontab.h | 55 | ||||
-rw-r--r-- | crond/delcron.c | 38 | ||||
-rw-r--r-- | crond/gcrond.h | 37 | ||||
-rw-r--r-- | crond/main.c | 135 | ||||
-rw-r--r-- | crond/rdcron.c | 503 | ||||
-rw-r--r-- | crond/runjob.c | 86 | ||||
-rw-r--r-- | docs/cmdline.md | 4 | ||||
-rw-r--r-- | docs/gcron.md | 62 |
18 files changed, 2 insertions, 1266 deletions
diff --git a/Makefile.am b/Makefile.am index f818627..5d38113 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,7 +21,6 @@ dist_man8_MANS = include lib/Makemodule.am include cmd/Makemodule.am include initd/Makemodule.am -include crond/Makemodule.am install-exec-hook: (cd $(DESTDIR)$(sbindir); $(LN_S) shutdown reboot) @@ -31,6 +30,3 @@ install-data-local: (cd $(DESTDIR)$(man8dir); $(LN_S) shutdown.8 reboot.8) $(MKDIR_P) $(DESTDIR)$(SVCDIR) $(MKDIR_P) $(DESTDIR)$(TEMPLATEDIR) -if GCROND - $(MKDIR_P) $(DESTDIR)$(GCRONDIR) -endif @@ -1,9 +1,8 @@ # About This directory contains the source code for a tiny service supervision -framework devised for the Pygos system, consisting of an init daemon, -a _definitely_ non standards compliant cron implementation and various -command line utilities. +framework devised for the Pygos system, consisting of an init daemon and +accompanying command line utilities. The programs of this package are developed first and foremost for GNU/Linux @@ -46,8 +45,6 @@ command line tools. See [docs/services.md](docs/services.md) for more information on service description files. -See [docs/gcron.md](docs/gcron.md) for details on the cron implementation. - ## Why diff --git a/cmd/Makemodule.am b/cmd/Makemodule.am index ea25ea8..07b50ce 100644 --- a/cmd/Makemodule.am +++ b/cmd/Makemodule.am @@ -26,11 +26,6 @@ service_CFLAGS = $(AM_CFLAGS) service_LDFLAGS = $(AM_LDFLAGS) service_LDADD = libinit.a libcfg.a libutil.a -if GCROND -service_SOURCES += cmd/service/schedule.c -service_SOURCES += cmd/service/unschedule.c -endif - dist_man8_MANS += cmd/shutdown.8 cmd/service/service.8 EXTRA_DIST += $(SRVHEADERS) diff --git a/cmd/service/schedule.c b/cmd/service/schedule.c deleted file mode 100644 index 41a4f1d..0000000 --- a/cmd/service/schedule.c +++ /dev/null @@ -1,90 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * Copyright (C) 2018 - David Oberhollenzer - * - * 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 <https://www.gnu.org/licenses/>. - */ -#include <sys/types.h> -#include <sys/stat.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdio.h> -#include <errno.h> - -#include "servicecmd.h" - -static int cmd_schedule(int argc, char **argv) -{ - char *target, *linkname, *ptr; - int ret = EXIT_FAILURE; - struct stat sb; - - if (check_arguments(argv[0], argc, 2, 2)) - return EXIT_FAILURE; - - for (ptr = argv[1]; isalnum(*ptr) || *ptr == '_'; ++ptr) - ; - - if (*ptr != '\0') { - fprintf(stderr, "Invalid service name '%s'\n", argv[1]); - tell_read_help(argv[0]); - return EXIT_FAILURE; - } - - if (asprintf(&target, "%s/%s.gcron", TEMPLATEDIR, argv[1]) < 0) { - perror("asprintf"); - return EXIT_FAILURE; - } - - if (stat(target, &sb)) { - fprintf(stderr, "%s: %s\n", target, strerror(errno)); - goto out_tgt; - } - - if ((sb.st_mode & S_IFMT) != S_IFREG) { - fprintf(stderr, "%s: must be a regular file\n", target); - goto out_tgt; - } - - if (asprintf(&linkname, "%s/%s", GCRONDIR, argv[1]) < 0) { - perror("asprintf"); - goto out_tgt; - } - - if (symlink(target, linkname)) { - fprintf(stderr, "creating symlink '%s' -> '%s: %s\n", - linkname, target, strerror(errno)); - goto out; - } - - ret = EXIT_SUCCESS; -out: - free(linkname); -out_tgt: - free(target); - return ret; -} - -static command_t schedule = { - .cmd = "schedule", - .usage = "<name>", - .s_desc = "enable a gcrond service", - .l_desc = "This marks a gcrond service as enabled by creating a " - "symlink in " GCRONDIR " pointing to a template file in " - TEMPLATEDIR " with a .gcron extension.", - .run_cmd = cmd_schedule, -}; - -REGISTER_COMMAND(schedule) diff --git a/cmd/service/service.8 b/cmd/service/service.8 index 3ca7cb2..139bdb5 100644 --- a/cmd/service/service.8 +++ b/cmd/service/service.8 @@ -28,12 +28,6 @@ configuration directory, pointing to the service template file. An optional argument can be supplied to parameterize the template. .TP -.BR schedule " " \fI<service>\fP -If built with support for gcrond, enable a gcron service by creating a symlink -in the gcrond configuration directory, pointing to the service file. - -The extension \fB.gcron\fP is automatically appended to the service name. -.TP .BR disable " " \fI<service>\fP " " \fI[arguments]\fP Disable (but do not stop) a system service by removing the corresponding symlink in the configuration directory. @@ -41,10 +35,6 @@ symlink in the configuration directory. If the service is parameterized, arguments have to be specified to disable the desired service instance. .TP -.BR unschedule " " \fI<service>\fP -If built with support for gcrond, disable a gcron service by removing the -corresponding symlink in the gcron configuration directory. -.TP .BR dumpscript " " \fI<service>\fP " " \fI[arguments]\fP Parse a service file from and produce a pseudo shell script containing the exact commands executed when starting the service. diff --git a/cmd/service/unschedule.c b/cmd/service/unschedule.c deleted file mode 100644 index aea6982..0000000 --- a/cmd/service/unschedule.c +++ /dev/null @@ -1,82 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * Copyright (C) 2018 - David Oberhollenzer - * - * 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 <https://www.gnu.org/licenses/>. - */ -#include <sys/types.h> -#include <sys/stat.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdio.h> -#include <errno.h> - -#include "servicecmd.h" - -static int cmd_unschedule(int argc, char **argv) -{ - int ret = EXIT_FAILURE; - char *linkname, *ptr; - struct stat sb; - - if (check_arguments(argv[0], argc, 2, 2)) - return EXIT_FAILURE; - - for (ptr = argv[1]; isalnum(*ptr) || *ptr == '_'; ++ptr) - ; - - if (*ptr != '\0') { - fprintf(stderr, "Invalid service name '%s'\n", argv[1]); - tell_read_help(argv[0]); - return EXIT_FAILURE; - } - - if (asprintf(&linkname, "%s/%s.gcron", GCRONDIR, argv[1]) < 0) { - perror("asprintf"); - return EXIT_FAILURE; - } - - if (lstat(linkname, &sb)) { - fprintf(stderr, "lstat %s: %s\n", linkname, strerror(errno)); - goto out; - } - - if ((sb.st_mode & S_IFMT) != S_IFLNK) { - fprintf(stderr, "error: '%s' is not a symlink!", linkname); - goto out; - } - - if (unlink(linkname)) { - fprintf(stderr, "removing %s: %s\n", - linkname, strerror(errno)); - goto out; - } - - ret = EXIT_SUCCESS; -out: - free(linkname); - return ret; -} - -static command_t unschedule = { - .cmd = "unschedule", - .usage = "<name>", - .s_desc = "disable a gcrond service", - .l_desc = "This disables a gcrond service by removing the coresponding " - "symlink in " GCRONDIR ".", - .run_cmd = cmd_unschedule, -}; - -REGISTER_COMMAND(unschedule) diff --git a/configure.ac b/configure.ac index 07964d9..bb747f5 100644 --- a/configure.ac +++ b/configure.ac @@ -36,20 +36,8 @@ UL_WARN_ADD([-pedantic]) AC_SUBST([WARN_CFLAGS]) - -AC_ARG_WITH([gcrond], - [AS_HELP_STRING([--without-gcrond], [Build without gcron daemon])], - [case "${withval}" in - yes) AM_CONDITIONAL([GCROND], [true]) ;; - no) AM_CONDITIONAL([GCROND], [false]) ;; - *) AC_MSG_ERROR([bad value ${withval} for --without-gcron]) ;; - esac], - [AM_CONDITIONAL([GCROND], [true])]) - - AC_CONFIG_HEADERS([lib/include/config.h]) AC_DEFINE_DIR(SVCDIR, sysconfdir/init.d, [Startup service directory]) -AC_DEFINE_DIR(GCRONDIR, sysconfdir/gcron.d, [Cron service directory]) AC_DEFINE_DIR(TEMPLATEDIR, datadir/init, [Service template directory]) AC_DEFINE_DIR(SCRIPTDIR, libexecdir/init, [Helper script directory]) AC_DEFINE_DIR(SOCKDIR, localstatedir/run, [Directory for initd socket]) diff --git a/crond/Makemodule.am b/crond/Makemodule.am deleted file mode 100644 index b2eb1c7..0000000 --- a/crond/Makemodule.am +++ /dev/null @@ -1,11 +0,0 @@ -if GCROND -gcrond_SOURCES = crond/main.c crond/gcrond.h crond/runjob.c -gcrond_SOURCES += crond/rdcron.c crond/delcron.c crond/crontab.c -gcrond_SOURCES += crond/cronscan.c crond/crontab.h -gcrond_CPPFLAGS = $(AM_CPPFLAGS) -gcrond_CFLAGS = $(AM_CFLAGS) -gcrond_LDFLAGS = $(AM_LDFLAGS) -gcrond_LDADD = libcfg.a libutil.a - -sbin_PROGRAMS += gcrond -endif diff --git a/crond/cronscan.c b/crond/cronscan.c deleted file mode 100644 index e28fb03..0000000 --- a/crond/cronscan.c +++ /dev/null @@ -1,77 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * Copyright (C) 2018 - David Oberhollenzer - * - * 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 <https://www.gnu.org/licenses/>. - */ -#include <sys/types.h> -#include <sys/stat.h> -#include <stddef.h> -#include <dirent.h> -#include <string.h> -#include <errno.h> -#include <stdio.h> -#include <fcntl.h> -#include <ctype.h> - -#include "crontab.h" - -int cronscan(const char *directory, crontab_t **list) -{ - struct dirent *ent; - int dfd, ret = 0; - crontab_t *cron; - DIR *dir; - - dir = opendir(directory); - if (dir == NULL) { - perror(directory); - return -1; - } - - dfd = dirfd(dir); - if (dfd < 0) { - perror(directory); - closedir(dir); - return -1; - } - - for (;;) { - errno = 0; - ent = readdir(dir); - - if (ent == NULL) { - if (errno != 0) { - perror(directory); - ret = -1; - } - break; - } - - if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) - continue; - - cron = rdcron(dfd, ent->d_name); - if (cron == NULL) { - ret = -1; - continue; - } - - cron->next = *list; - *list = cron; - } - - closedir(dir); - return ret; -} diff --git a/crond/crontab.c b/crond/crontab.c deleted file mode 100644 index f761ec0..0000000 --- a/crond/crontab.c +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * Copyright (C) 2018 - David Oberhollenzer - * - * 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 <https://www.gnu.org/licenses/>. - */ -#include <string.h> - -#include "crontab.h" - -void cron_tm_to_mask(crontab_t *out, struct tm *t) -{ - memset(out, 0, sizeof(*out)); - out->minute = 1UL << ((unsigned long)t->tm_min); - out->hour = 1 << t->tm_hour; - out->dayofmonth = 1 << (t->tm_mday - 1); - out->month = 1 << t->tm_mon; - out->dayofweek = 1 << t->tm_wday; -} - -bool cron_should_run(const crontab_t *t, const crontab_t *mask) -{ - if ((t->minute & mask->minute) == 0) - return false; - - if ((t->hour & mask->hour) == 0) - return false; - - if ((t->dayofmonth & mask->dayofmonth) == 0) - return false; - - if ((t->month & mask->month) == 0) - return false; - - if ((t->dayofweek & mask->dayofweek) == 0) - return false; - - return true; -} diff --git a/crond/crontab.h b/crond/crontab.h deleted file mode 100644 index 1ea3883..0000000 --- a/crond/crontab.h +++ /dev/null @@ -1,55 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * Copyright (C) 2018 - David Oberhollenzer - * - * 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 <https://www.gnu.org/licenses/>. - */ -#ifndef CRONTAB_H -#define CRONTAB_H - -#include <sys/types.h> -#include <stdbool.h> -#include <stdint.h> -#include <time.h> - -#include "service.h" - -typedef struct crontab_t { - struct crontab_t *next; - exec_t *exec; - char *ctty; - - uid_t uid; - gid_t gid; - - uint64_t minute; - uint32_t hour; - uint32_t dayofmonth; - uint16_t month; - uint8_t dayofweek; - - unsigned int tty_truncate : 1; -} crontab_t; - -crontab_t *rdcron(int dirfd, const char *filename); - -void delcron(crontab_t *cron); - -int cronscan(const char *directory, crontab_t **list); - -void cron_tm_to_mask(crontab_t *out, struct tm *t); - -bool cron_should_run(const crontab_t *t, const crontab_t *mask); - -#endif /* CRONTAB_H */ diff --git a/crond/delcron.c b/crond/delcron.c deleted file mode 100644 index 1877db1..0000000 --- a/crond/delcron.c +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * Copyright (C) 2018 - David Oberhollenzer - * - * 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 <https://www.gnu.org/licenses/>. - */ -#include <stdlib.h> - -#include "crontab.h" - -void delcron(crontab_t *cron) -{ - exec_t *e; - - if (cron == NULL) - return; - - while (cron->exec != NULL) { - e = cron->exec; - cron->exec = e->next; - - free(e); - } - - free(cron->ctty); - free(cron); -} diff --git a/crond/gcrond.h b/crond/gcrond.h deleted file mode 100644 index 4cc2417..0000000 --- a/crond/gcrond.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * Copyright (C) 2018 - David Oberhollenzer - * - * 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 <https://www.gnu.org/licenses/>. - */ -#ifndef GCROND_H -#define GCROND_H - -#include <sys/types.h> -#include <sys/wait.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <signal.h> -#include <stdio.h> -#include <errno.h> - -#include "crontab.h" -#include "config.h" -#include "util.h" - -int runjob(crontab_t *tab); - -#endif /* GCROND_H */ - diff --git a/crond/main.c b/crond/main.c deleted file mode 100644 index 613a1ae..0000000 --- a/crond/main.c +++ /dev/null @@ -1,135 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * Copyright (C) 2018 - David Oberhollenzer - * - * 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 <https://www.gnu.org/licenses/>. - */ -#include "gcrond.h" - -static crontab_t *jobs; -static sig_atomic_t run = 1; -static sig_atomic_t rescan = 1; - -static void read_config(void) -{ - if (cronscan(GCRONDIR, &jobs)) { - fputs("Error reading configuration. Continuing anyway.\n", - stderr); - } -} - -static void cleanup_config(void) -{ - crontab_t *t; - - while (jobs != NULL) { - t = jobs; - jobs = jobs->next; - delcron(t); - } -} - -static int calc_timeout(void) -{ - time_t now = time(NULL), future; - struct tm tmstruct; - crontab_t mask, *t; - int minutes; - - for (minutes = 0; minutes < 120; ++minutes) { - future = now + minutes * 60; - - localtime_r(&future, &tmstruct); - cron_tm_to_mask(&mask, &tmstruct); - - for (t = jobs; t != NULL; t = t->next) { - if (cron_should_run(t, &mask)) - goto out; - } - } -out: - return minutes ? minutes * 60 : 60; -} - -static void runjobs(void) -{ - time_t now = time(NULL); - struct tm tmstruct; - crontab_t mask, *t; - - localtime_r(&now, &tmstruct); - cron_tm_to_mask(&mask, &tmstruct); - - for (t = jobs; t != NULL; t = t->next) { - if (cron_should_run(t, &mask)) - runjob(t); - } -} - -static void sighandler(int signo) -{ - pid_t pid; - - switch (signo) { - case SIGINT: - case SIGTERM: - run = 0; - break; - case SIGHUP: - rescan = 1; - break; - case SIGCHLD: - while ((pid = waitpid(-1, NULL, WNOHANG)) != -1) - ; - break; - } -} - -int main(void) -{ - struct timespec stime; - struct sigaction act; - int timeout; - - memset(&act, 0, sizeof(act)); - act.sa_handler = sighandler; - sigaction(SIGINT, &act, NULL); - sigaction(SIGTERM, &act, NULL); - sigaction(SIGHUP, &act, NULL); - sigaction(SIGCHLD, &act, NULL); - - while (run) { - if (rescan == 1) { - cleanup_config(); - read_config(); - timeout = 60; - rescan = 0; - } else { - runjobs(); - timeout = calc_timeout(); - } - - stime.tv_sec = timeout; - stime.tv_nsec = 0; - - while (nanosleep(&stime, &stime) != 0 && run && !rescan) { - if (errno != EINTR) { - perror("nanosleep"); - break; - } - } - } - - return EXIT_SUCCESS; -} diff --git a/crond/rdcron.c b/crond/rdcron.c deleted file mode 100644 index 8781a6f..0000000 --- a/crond/rdcron.c +++ /dev/null @@ -1,503 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * Copyright (C) 2018 - David Oberhollenzer - * - * 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 <https://www.gnu.org/licenses/>. - */ -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <string.h> -#include <stdlib.h> -#include <limits.h> -#include <stdio.h> -#include <errno.h> -#include <fcntl.h> -#include <ctype.h> -#include <pwd.h> -#include <grp.h> - -#include "crontab.h" -#include "libcfg.h" -#include "util.h" - - -static const enum_map_t weekday[] = { - { "MON", 1 }, - { "TUE", 2 }, - { "WED", 3 }, - { "THU", 4 }, - { "FRI", 5 }, - { "SAT", 6 }, - { "SUN", 0 }, -}; - -static const enum_map_t month[] = { - { "JAN", 1 }, - { "FEB", 2 }, - { "MAR", 3 }, - { "APR", 4 }, - { "MAY", 5 }, - { "JUN", 6 }, - { "JUL", 7 }, - { "AUG", 8 }, - { "SEP", 9 }, - { "OCT", 10 }, - { "NOV", 11 }, - { "DEC", 12 }, -}; - -static const struct { - const char *macro; - crontab_t tab; -} intervals[] = { - { - .macro = "yearly", - .tab = { - .minute = 0x01, - .hour = 0x01, - .dayofmonth = 0x01, - .month = 0x01, - .dayofweek = 0xFF - }, - }, { - .macro = "annually", - .tab = { - .minute = 0x01, - .hour = 0x01, - .dayofmonth = 0x01, - .month = 0x01, - .dayofweek = 0xFF - }, - }, { - .macro = "monthly", - .tab = { - .minute = 0x01, - .hour = 0x01, - .dayofmonth = 0x01, - .month = 0xFFFF, - .dayofweek = 0xFF - }, - }, { - .macro = "weekly", - .tab = { - .minute = 0x01, - .hour = 0x01, - .dayofmonth = 0xFFFFFFFF, - .month = 0xFFFF, - .dayofweek = 0x01 - }, - }, { - .macro = "daily", - .tab = { - .minute = 0x01, - .hour = 0x01, - .dayofmonth = 0xFFFFFFFF, - .month = 0xFFFF, - .dayofweek = 0xFF - }, - }, { - .macro = "hourly", - .tab = { - .minute = 0x01, - .hour = 0xFFFFFFFF, - .dayofmonth = 0xFFFFFFFF, - .month = 0xFFFF, - .dayofweek = 0xFF - }, - }, -}; - -/*****************************************************************************/ - -static int try_unescape(char *arg, rdline_t *rd) -{ - if (unescape(arg)) { - fprintf(stderr, "%s: %zu: malformed string constant\n", - rd->filename, rd->lineno); - return -1; - } - return 0; -} - -static char *try_strdup(const char *str, rdline_t *rd) -{ - char *out = strdup(str); - - if (out == NULL) { - fprintf(stderr, "%s: %zu: out of memory\n", - rd->filename, rd->lineno); - } - return out; -} - -static char *readnum(char *line, int *out, int minval, int maxval, - const enum_map_t *mnemonic, rdline_t *rd) -{ - int i, temp, value = 0; - const enum_map_t *ev; - - if (!isdigit(*line)) { - if (!mnemonic) - goto fail_mn; - - for (i = 0; isalnum(line[i]); ++i) - ; - if (i == 0) - goto fail_mn; - - temp = line[i]; - line[i] = '\0'; - ev = enum_by_name(mnemonic, line); - if (!ev) { - fprintf(stderr, "%s: %zu: unexpected '%s'", - rd->filename, rd->lineno, line); - } - line[i] = temp; - if (!ev) - return NULL; - *out = ev->value; - return line + i; - } - - while (isdigit(*line)) { - i = ((*(line++)) - '0'); - if (value > (maxval - i) / 10) - goto fail_of; - value = value * 10 + i; - } - - if (value < minval) - goto fail_uf; - - *out = value; - return line; -fail_of: - fprintf(stderr, "%s: %zu: value exceeds maximum (%d > %d)\n", - rd->filename, rd->lineno, value, maxval); - return NULL; -fail_uf: - fprintf(stderr, "%s: %zu: value too small (%d < %d)\n", - rd->filename, rd->lineno, value, minval); - return NULL; -fail_mn: - fprintf(stderr, "%s: %zu: expected numeric value", - rd->filename, rd->lineno); - return NULL; -} - -static char *readfield(char *line, uint64_t *out, int minval, int maxval, - const enum_map_t *mnemonic, rdline_t *rd) -{ - int value, endvalue, step; - uint64_t v = 0; -next: - if (*line == '*') { - ++line; - value = minval; - endvalue = maxval; - } else { - line = readnum(line, &value, minval, maxval, mnemonic, rd); - if (!line) - goto fail; - - if (*line == '-') { - line = readnum(line + 1, &endvalue, minval, maxval, - mnemonic, rd); - if (!line) - goto fail; - } else { - endvalue = value; - } - } - - if (endvalue < value) - goto fail; - - if (*line == '/') { - line = readnum(line + 1, &step, 1, maxval + 1, NULL, rd); - if (!line) - goto fail; - } else { - step = 1; - } - - while (value <= endvalue) { - v |= 1UL << (unsigned long)(value - minval); - value += step; - } - - if (*line == ',' || *line == ' ') { - ++line; - goto next; - } - - if (*line != '\0') - goto fail; - - *out = v; - return line; -fail: - fprintf(stderr, "%s: %zu: invalid time range expression\n", - rd->filename, rd->lineno); - return NULL; -} - -/*****************************************************************************/ - -static int cron_exec(void *user, char *arg, rdline_t *rd, int flags) -{ - crontab_t *cron = user; - exec_t *e, *end; - (void)flags; - - e = calloc(1, sizeof(*e) + strlen(arg) + 1); - if (e == NULL) { - fprintf(stderr, "%s: %zu: out of memory\n", - rd->filename, rd->lineno); - return -1; - } - - strcpy(e->args, arg); - - e->argc = pack_argv(e->args); - if (e->argc < 0) { - fprintf(stderr, "%s: %zu: malformed string constant\n", - rd->filename, rd->lineno); - return -1; - } - - if (cron->exec == NULL) { - cron->exec = e; - } else { - for (end = cron->exec; end->next != NULL; end = end->next) - ; - end->next = e; - } - return 0; -} - -static int cron_hour(void *user, char *arg, rdline_t *rd, int flags) -{ - crontab_t *cron = user; - uint64_t value; - (void)flags; - - if (!readfield(arg, &value, 0, 23, NULL, rd)) - return -1; - - cron->hour = value; - return 0; -} - -static int cron_minute(void *user, char *arg, rdline_t *rd, int flags) -{ - crontab_t *cron = user; - uint64_t value; - (void)flags; - - if (!readfield(arg, &value, 0, 59, NULL, rd)) - return -1; - - cron->minute = value; - return 0; -} - -static int cron_dayofmonth(void *user, char *arg, rdline_t *rd, int flags) -{ - crontab_t *cron = user; - uint64_t value; - (void)flags; - - if (!readfield(arg, &value, 1, 31, NULL, rd)) - return -1; - - cron->dayofmonth = value; - return 0; -} - -static int cron_dayofweek(void *user, char *arg, rdline_t *rd, int flags) -{ - crontab_t *cron = user; - uint64_t value; - (void)flags; - - if (!readfield(arg, &value, 0, 6, weekday, rd)) - return -1; - - cron->dayofweek = value; - return 0; -} - -static int cron_month(void *user, char *arg, rdline_t *rd, int flags) -{ - crontab_t *cron = user; - uint64_t value; - (void)flags; - - if (!readfield(arg, &value, 1, 12, month, rd)) - return -1; - - cron->month = value; - return 0; -} - -static int cron_interval(void *user, char *arg, rdline_t *rd, int flags) -{ - crontab_t *cron = user; - size_t i; - (void)flags; - - for (i = 0; i < ARRAY_SIZE(intervals); ++i) { - if (!strcmp(intervals[i].macro, arg)) { - cron->minute = intervals[i].tab.minute; - cron->hour = intervals[i].tab.hour; - cron->dayofmonth = intervals[i].tab.dayofmonth; - cron->month = intervals[i].tab.month; - cron->dayofweek = intervals[i].tab.dayofweek; - return 0; - } - } - - fprintf(stderr, "%s: %zu: unknown interval '%s'\n", - rd->filename, rd->lineno, arg); - return -1; -} - -static int cron_user(void *user, char *arg, rdline_t *rd, int flags) -{ - crontab_t *cron = user; - struct passwd *pwd; - bool isnumeric; - char *ptr; - int value; - (void)flags; - - for (ptr = arg; isdigit(*ptr); ++ptr) - ; - - isnumeric = (*ptr == '\0'); - pwd = getpwnam(arg); - - if (pwd == NULL && !isnumeric) { - fprintf(stderr, "%s: %zu: unknown user '%s'\n", - rd->filename, rd->lineno, arg); - return -1; - } - - if (pwd != NULL) { - cron->uid = pwd->pw_uid; - } else { - if (readnum(arg, &value, 0, INT_MAX, NULL, rd)) - return -1; - cron->uid = value; - } - return 0; -} - -static int cron_group(void *user, char *arg, rdline_t *rd, int flags) -{ - crontab_t *cron = user; - struct group *group; - bool isnumeric; - char *ptr; - int value; - (void)flags; - - for (ptr = arg; isdigit(*ptr); ++ptr) - ; - - isnumeric = (*ptr == '\0'); - group = getgrnam(arg); - - if (group == NULL && !isnumeric) { - fprintf(stderr, "%s: %zu: unknown group '%s'\n", - rd->filename, rd->lineno, arg); - return -1; - } - - if (group != NULL) { - cron->gid = group->gr_gid; - } else { - if (readnum(arg, &value, 0, INT_MAX, NULL, rd)) - return -1; - cron->gid = value; - } - return 0; -} - -static int cron_tty(void *user, char *arg, rdline_t *rd, int flags) -{ - crontab_t *cron = user; - (void)flags; - - if (strncmp(arg, "truncate", 8) == 0 && isspace(arg[8])) { - cron->tty_truncate = 1; - arg += 8; - while (isspace(*arg)) - ++arg; - } - - if (try_unescape(arg, rd)) - return -1; - - cron->ctty = try_strdup(arg, rd); - return cron->ctty == NULL ? -1 : 0; -} - - - -static const cfg_param_t cron_params[] = { - { "hour", 0, cron_hour }, - { "minute", 0, cron_minute }, - { "dayofmonth", 0, cron_dayofmonth }, - { "dayofweek", 0, cron_dayofweek }, - { "month", 0, cron_month }, - { "interval", 0, cron_interval }, - { "user", 0, cron_user }, - { "group", 0, cron_group }, - { "tty", 0, cron_tty }, - { "exec", 1, cron_exec }, -}; - -crontab_t *rdcron(int dirfd, const char *filename) -{ - crontab_t *cron = NULL; - rdline_t rd; - int ret; - - if (rdline_init(&rd, dirfd, filename, 0, NULL)) - return NULL; - - cron = calloc(1, sizeof(*cron)); - if (cron == NULL) { - fputs("out of memory\n", stderr); - goto out; - } - - cron->minute = 0xFFFFFFFFFFFFFFFFUL; - cron->hour = 0xFFFFFFFF; - cron->dayofmonth = 0xFFFFFFFF; - cron->month = 0xFFFF; - cron->dayofweek = 0xFF; - - ret = rdcfg(cron, &rd, cron_params, ARRAY_SIZE(cron_params), 0); - if (ret) { - delcron(cron); - cron = NULL; - } -out: - rdline_cleanup(&rd); - return cron; -} diff --git a/crond/runjob.c b/crond/runjob.c deleted file mode 100644 index 83c4278..0000000 --- a/crond/runjob.c +++ /dev/null @@ -1,86 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * Copyright (C) 2018 - David Oberhollenzer - * - * 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 <https://www.gnu.org/licenses/>. - */ -#include "gcrond.h" - -int runjob(crontab_t *tab) -{ - struct sigaction act; - pid_t pid; - exec_t *e; - int ret; - - if (tab->exec == NULL) - return 0; - - pid = fork(); - if (pid == -1) { - perror("fork"); - return -1; - } - - if (pid != 0) - return 0; - - /* XXX: inside the child process */ - memset(&act, 0, sizeof(act)); - act.sa_handler = SIG_DFL; - sigaction(SIGINT, &act, NULL); - sigaction(SIGTERM, &act, NULL); - sigaction(SIGHUP, &act, NULL); - sigaction(SIGCHLD, &act, NULL); - - if (setup_tty(tab->ctty, tab->tty_truncate)) - exit(EXIT_FAILURE); - - if (tab->gid != 0) { - if (setresgid(tab->gid, tab->gid, tab->gid)) { - perror("setgid"); - exit(EXIT_FAILURE); - } - } - - if (tab->uid != 0) { - if (setresuid(tab->uid, tab->uid, tab->uid)) { - perror("setuid"); - exit(EXIT_FAILURE); - } - } - - if (tab->exec->next == NULL) - argv_exec(tab->exec); - - for (e = tab->exec; e != NULL; e = e->next) { - pid = fork(); - if (pid == -1) { - perror("fork"); - exit(EXIT_FAILURE); - } - - if (pid == 0) - argv_exec(e); - - while (waitpid(pid, &ret, 0) != pid) - ; - - ret = WIFEXITED(ret) ? WEXITSTATUS(ret) : EXIT_FAILURE; - if (ret != EXIT_SUCCESS) - break; - } - - exit(ret); -} diff --git a/docs/cmdline.md b/docs/cmdline.md index e47cd8e..8967e4a 100644 --- a/docs/cmdline.md +++ b/docs/cmdline.md @@ -13,10 +13,6 @@ Currently available service commands are: * disable - disable a service. If the service is parameterized, requires the same arguments used for enabling, to disable the specific instance of the service. - * schedule - enable a gcrond service. Only available if this package is built - with gcrond. - * unschedule - disnable a gcrond service. Only available if this package is - built with gcrond. * dumpscript - generate an equivalent shell script from the `exec` lines of a service after applying all parameter substitutions. * list - list all enabled service. A target can be specified to only list diff --git a/docs/gcron.md b/docs/gcron.md deleted file mode 100644 index 4327083..0000000 --- a/docs/gcron.md +++ /dev/null @@ -1,62 +0,0 @@ -# Gcron - -Gcron is a small daemon that executes batch commands once a certain -condition is met. - -In a typical installation, it reads configuration files from `/etc/gcron.d`. -If used together with the init system in this package, the `service` command -can be used to administer symlinks in that directory, pointing -to `/usr/share/init/<name>.gcron`. - -Each file in the configuration directory represents a single scheduled batch -job. The syntax and most of the keywords are similar to `initd` service files -(See [services.md](services.md)). - -## Cron Style Patterns - -The following keywords can be used to specify classic cron style patterns for -when a job should be run: - - * `hour` - * `minute` - * `dayofmonth` - * `dayofweek` - * `month` - -For each of those keywords, a comma separated sequence of times can be -specified. Time ranges can be specified using the syntax `<start>-<end>`, -or using `*` for every possible value. A sequence (either range or star) -can be suffixed with `/<step>` to specify an increment. -For instance, `minute */5` means every five minutes and `minute 15-30/2` -means every two minutes between quarter past and half past. - -In addition to numeric values, the keywords `dayofweek` and `month` allow -specifying 3 letter, uppercase week day and moth names such as `MON`, `TUE`, -etc and `JAN`, `FEB`, ... - -The job is only run when all specified conditions are met. Omitting a field -is the same as specifying `*`. - -## Named Intervals - -Alternatively to the above, the keyword `interval` can be used. The following -intervals can be specified: - - * `yearly` or `annually` means on every January the first at midnight. - * `monthly` means on every first of the month at midnight. - * `weekly` means every Sunday at midnight. - * `daily` means every day at midnight. - * `hourly` means every first minute of the hour. - -## Command Specification - -To specify *what* should be done once the condition is met, the following -keywords can be used: - - * `exec` - the command to run. Multiple commands can be grouped - using curly braces. - * `user` - a user name or ID to set before running the commands. - * `group` - a group name or ID to set before running the commands. - * `tty` - similar to init service files, the controlling tty or output file - for the batch commands. Like init service files, the `truncate` keyword - can be used. |