aboutsummaryrefslogtreecommitdiff
path: root/crond
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@tele2.at>2018-09-16 21:52:46 +0200
committerDavid Oberhollenzer <david.oberhollenzer@tele2.at>2018-09-19 12:22:14 +0200
commitf38163772cb8ca25c440393132e8678e65437320 (patch)
treee0ad42ce3b374dda60ce92eab7f2f5fbca8722b4 /crond
parent5cd5f48f765f00b81786c6f569314474a91a06b8 (diff)
Add simple cron implementation
Signed-off-by: David Oberhollenzer <david.oberhollenzer@tele2.at>
Diffstat (limited to 'crond')
-rw-r--r--crond/Makemodule.am9
-rw-r--r--crond/gcrond.h37
-rw-r--r--crond/main.c139
-rw-r--r--crond/runjob.c87
4 files changed, 272 insertions, 0 deletions
diff --git a/crond/Makemodule.am b/crond/Makemodule.am
new file mode 100644
index 0000000..51960e9
--- /dev/null
+++ b/crond/Makemodule.am
@@ -0,0 +1,9 @@
+if GCROND
+gcrond_SOURCES = crond/main.c crond/gcrond.h crond/runjob.c
+gcrond_CPPFLAGS = $(AM_CPPFLAGS)
+gcrond_CFLAGS = $(AM_CFLAGS)
+gcrond_LDFLAGS = $(AM_LDFLAGS)
+gcrond_LDADD = libcron.a libinit.a libcfg.a
+
+sbin_PROGRAMS += gcrond
+endif
diff --git a/crond/gcrond.h b/crond/gcrond.h
new file mode 100644
index 0000000..4cc2417
--- /dev/null
+++ b/crond/gcrond.h
@@ -0,0 +1,37 @@
+/* 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
new file mode 100644
index 0000000..d7cc33e
--- /dev/null
+++ b/crond/main.c
@@ -0,0 +1,139 @@
+/* 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)
+{
+ switch (signo) {
+ case SIGINT:
+ case SIGTERM:
+ run = 0;
+ break;
+ case SIGHUP:
+ rescan = 1;
+ break;
+ }
+}
+
+int main(void)
+{
+ struct timespec stime;
+ struct sigaction act;
+ crontab_t *t;
+ int timeout;
+ pid_t pid;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = sighandler;
+ sigaction(SIGINT, &act, NULL);
+ sigaction(SIGTERM, &act, NULL);
+ sigaction(SIGHUP, &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;
+ }
+ }
+
+ while ((pid = waitpid(-1, NULL, WNOHANG)) != -1) {
+ for (t = jobs; t != NULL; t = t->next) {
+ if (t->pid == pid) {
+ t->pid = -1;
+ break;
+ }
+ }
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/crond/runjob.c b/crond/runjob.c
new file mode 100644
index 0000000..7650748
--- /dev/null
+++ b/crond/runjob.c
@@ -0,0 +1,87 @@
+/* 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) {
+ tab->pid = pid;
+ 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);
+
+ 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);
+}