diff options
Diffstat (limited to 'crond')
| -rw-r--r-- | crond/Makemodule.am | 9 | ||||
| -rw-r--r-- | crond/gcrond.h | 37 | ||||
| -rw-r--r-- | crond/main.c | 139 | ||||
| -rw-r--r-- | crond/runjob.c | 87 | 
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); +}  | 
