aboutsummaryrefslogtreecommitdiff
path: root/gcrond.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcrond.c')
-rw-r--r--gcrond.c128
1 files changed, 128 insertions, 0 deletions
diff --git a/gcrond.c b/gcrond.c
new file mode 100644
index 0000000..0e28277
--- /dev/null
+++ b/gcrond.c
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: ISC */
+#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 timeout_minutes(int minutes)
+{
+ time_t now = time(NULL);
+ struct tm t;
+
+ localtime_r(&now, &t);
+ return minutes * 60 + 30 - t.tm_sec;
+}
+
+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 timeout_minutes(minutes ? minutes : 1);
+}
+
+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 = timeout_minutes(1);
+ 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;
+}