diff options
| author | David Oberhollenzer <david.oberhollenzer@tele2.at> | 2018-09-16 21:52:46 +0200 | 
|---|---|---|
| committer | David Oberhollenzer <david.oberhollenzer@tele2.at> | 2018-09-19 12:22:14 +0200 | 
| commit | f38163772cb8ca25c440393132e8678e65437320 (patch) | |
| tree | e0ad42ce3b374dda60ce92eab7f2f5fbca8722b4 /crond/main.c | |
| parent | 5cd5f48f765f00b81786c6f569314474a91a06b8 (diff) | |
Add simple cron implementation
Signed-off-by: David Oberhollenzer <david.oberhollenzer@tele2.at>
Diffstat (limited to 'crond/main.c')
| -rw-r--r-- | crond/main.c | 139 | 
1 files changed, 139 insertions, 0 deletions
| 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; +} | 
