cron(8): add support for /etc/cron.d and /usr/local/etc/cron.d

For automation tools it is way easier to maintain files in directories rather
than modifying /etc/crontab.

The files in those directories are in the same format as /etc/crontab

Reviewed by:	adrian
MFC after:	2 weeks
Relnotes:	yes
Sponsored by:	Gandi.net
Differential Revision:	https://reviews.freebsd.org/D8400
This commit is contained in:
Baptiste Daroussin 2016-10-31 18:20:12 +00:00
parent ae8b1f90fe
commit b2fd8384ff
6 changed files with 56 additions and 10 deletions

View File

@ -32,6 +32,8 @@
..
casper
..
cron.d
..
defaults
..
devd

View File

@ -17,7 +17,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd August 21, 2016
.Dd Octobre 31, 2016
.Dt CRON 8
.Os
.Sh NAME
@ -53,7 +53,11 @@ The
.Nm
utility also searches for
.Pa /etc/crontab
which is in a different format (see
and files in
.Pa /etc/cron.d
and
.Pa /usr/local/etc/cron.d
which are in a different format (see
.Xr crontab 5 ) .
.Pp
The

View File

@ -218,7 +218,7 @@ void set_cron_uid(void),
unget_char(int, FILE *),
free_entry(entry *),
skip_comments(FILE *),
log_it(char *, int, char *, char *),
log_it(char *, int, char *, const char *),
log_close(void);
int job_runqueue(void),

View File

@ -45,9 +45,18 @@ load_database(old_db)
DIR *dir;
struct stat statbuf;
struct stat syscron_stat;
time_t maxmtime;
DIR_T *dp;
cron_db new_db;
user *u, *nu;
struct {
const char *name;
struct stat st;
} syscrontabs [] = {
{ SYSCRONTABS },
{ LOCALSYSCRONTABS }
};
int i;
Debug(DLOAD, ("[%d] load_database()\n", getpid()))
@ -65,6 +74,16 @@ load_database(old_db)
if (stat(SYSCRONTAB, &syscron_stat) < OK)
syscron_stat.st_mtime = 0;
maxmtime = TMAX(statbuf.st_mtime, syscron_stat.st_mtime);
for (i = 0; i < nitems(syscrontabs); i++) {
if (stat(syscrontabs[i].name, &syscrontabs[i].st) != -1) {
maxmtime = TMAX(syscrontabs[i].st.st_mtime, maxmtime);
} else {
syscrontabs[i].st.st_mtime = 0;
}
}
/* if spooldir's mtime has not changed, we don't need to fiddle with
* the database.
*
@ -72,7 +91,7 @@ load_database(old_db)
* so is guaranteed to be different than the stat() mtime the first
* time this function is called.
*/
if (old_db->mtime == TMAX(statbuf.st_mtime, syscron_stat.st_mtime)) {
if (old_db->mtime == maxmtime) {
Debug(DLOAD, ("[%d] spool dir mtime unch, no load needed.\n",
getpid()))
return;
@ -83,7 +102,7 @@ load_database(old_db)
* actually changed. Whatever is left in the old database when
* we're done is chaff -- crontabs that disappeared.
*/
new_db.mtime = TMAX(statbuf.st_mtime, syscron_stat.st_mtime);
new_db.mtime = maxmtime;
new_db.head = new_db.tail = NULL;
if (syscron_stat.st_mtime) {
@ -92,6 +111,29 @@ load_database(old_db)
&new_db, old_db);
}
for (i = 0; i < nitems(syscrontabs); i++) {
char tabname[MAXPATHLEN];
if (syscrontabs[i].st.st_mtime == 0)
continue;
if (!(dir = opendir(syscrontabs[i].name))) {
log_it("CRON", getpid(), "OPENDIR FAILED",
syscrontabs[i].name);
(void) exit(ERROR_EXIT);
}
while (NULL != (dp = readdir(dir))) {
if (dp->d_name[0] == '.')
continue;
if (dp->d_type != DT_REG)
continue;
snprintf(tabname, sizeof(tabname), "%s/%s",
syscrontabs[i].name, dp->d_name);
process_crontab("root", SYS_NAME, tabname,
&syscrontabs[i].st, &new_db, old_db);
}
closedir(dir);
}
/* we used to keep this dir open all the time, for the sake of
* efficiency. however, we need to close it in every fork, and
* we fork a lot more often than the mtime of the dir changes.

View File

@ -62,6 +62,8 @@
/* 4.3BSD-style crontab */
#define SYSCRONTAB "/etc/crontab"
#define SYSCRONTABS "/etc/cron.d"
#define LOCALSYSCRONTABS "/usr/local/etc/cron.d"
/* what editor to use if no EDITOR or VISUAL
* environment variable specified.

View File

@ -385,11 +385,7 @@ out: if (allow)
void
log_it(username, xpid, event, detail)
char *username;
int xpid;
char *event;
char *detail;
log_it(char *username, int xpid, char *event, const char *detail)
{
#if defined(LOG_FILE) || DEBUGGING
PID_T pid = xpid;