#if !defined(lint) && !defined(LINT)
static const char rcsid[] =
"$Id: database.c,v 1.3 1998/08/14 00:32:38 vixie Exp $";
#endif
#include "cron.h"
#define TMAX(a,b) ((a)>(b)?(a):(b))
static void process_crontab(const char *, const char *,
const char *, struct stat *,
cron_db *, cron_db *);
void
load_database(cron_db *old_db)
{
struct stat statbuf, syscron_stat, st;
cron_db new_db;
DIR_T *dp;
DIR *dir;
user *u, *nu;
time_t maxmtime;
struct {
const char *name;
struct stat st;
} syscrontabs [] = {
{ SYSCRONTABS },
{ LOCALSYSCRONTABS }
};
int i, ret;
Debug(DLOAD, ("[%d] load_database()\n", getpid()))
if (stat(SPOOL_DIR, &statbuf) < OK) {
log_it("CRON", getpid(), "STAT FAILED", SPOOL_DIR);
(void) exit(ERROR_EXIT);
}
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);
if (!(dir = opendir(syscrontabs[i].name)))
continue;
while (NULL != (dp = readdir(dir))) {
if (dp->d_name[0] == '.')
continue;
ret = fstatat(dirfd(dir), dp->d_name, &st, 0);
if (ret != 0 || !S_ISREG(st.st_mode))
continue;
maxmtime = TMAX(st.st_mtime, maxmtime);
}
closedir(dir);
} else {
syscrontabs[i].st.st_mtime = 0;
}
}
if (old_db->mtime == maxmtime) {
Debug(DLOAD, ("[%d] spool dir mtime unch, no load needed.\n",
getpid()))
return;
}
new_db.mtime = maxmtime;
new_db.head = new_db.tail = NULL;
if (syscron_stat.st_mtime) {
process_crontab("root", SYS_NAME,
SYSCRONTAB, &syscron_stat,
&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 (fstatat(dirfd(dir), dp->d_name, &st, 0) == 0 &&
!S_ISREG(st.st_mode))
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);
}
if (!(dir = opendir(SPOOL_DIR))) {
log_it("CRON", getpid(), "OPENDIR FAILED", SPOOL_DIR);
(void) exit(ERROR_EXIT);
}
while (NULL != (dp = readdir(dir))) {
char fname[MAXNAMLEN+1], tabname[MAXNAMLEN+1];
if (dp->d_name[0] == '.')
continue;
(void) strncpy(fname, dp->d_name, sizeof(fname));
fname[sizeof(fname)-1] = '\0';
if (snprintf(tabname, sizeof tabname, CRON_TAB(fname))
>= sizeof(tabname))
continue;
process_crontab(fname, fname, tabname,
&statbuf, &new_db, old_db);
}
closedir(dir);
endpwent();
Debug(DLOAD, ("unlinking old database:\n"))
for (u = old_db->head; u != NULL; u = nu) {
Debug(DLOAD, ("\t%s\n", u->name))
nu = u->next;
unlink_user(old_db, u);
free_user(u);
}
*old_db = new_db;
Debug(DLOAD, ("load_database is done\n"))
}
void
link_user(cron_db *db, user *u)
{
if (db->head == NULL)
db->head = u;
if (db->tail)
db->tail->next = u;
u->prev = db->tail;
u->next = NULL;
db->tail = u;
}
void
unlink_user(cron_db *db, user *u)
{
if (u->prev == NULL)
db->head = u->next;
else
u->prev->next = u->next;
if (u->next == NULL)
db->tail = u->prev;
else
u->next->prev = u->prev;
}
user *
find_user(cron_db *db, const char *name)
{
user *u;
for (u = db->head; u != NULL; u = u->next)
if (strcmp(u->name, name) == 0)
break;
return (u);
}
static void
process_crontab(const char *uname, const char *fname, const char *tabname,
struct stat *statbuf, cron_db *new_db, cron_db *old_db)
{
struct passwd *pw = NULL;
int crontab_fd = OK - 1;
user *u;
entry *e;
time_t now;
if (strcmp(fname, SYS_NAME) != 0 && !(pw = getpwnam(uname))) {
log_it(fname, getpid(), "ORPHAN", "no passwd entry");
goto next_crontab;
}
if ((crontab_fd = open(tabname, O_RDONLY, 0)) < OK) {
log_it(fname, getpid(), "CAN'T OPEN", tabname);
goto next_crontab;
}
if (fstat(crontab_fd, statbuf) < OK) {
log_it(fname, getpid(), "FSTAT FAILED", tabname);
goto next_crontab;
}
Debug(DLOAD, ("\t%s:", fname))
u = find_user(old_db, fname);
if (u != NULL) {
if (u->mtime == statbuf->st_mtime) {
Debug(DLOAD, (" [no change, using old data]"))
unlink_user(old_db, u);
link_user(new_db, u);
goto next_crontab;
}
Debug(DLOAD, (" [delete old data]"))
unlink_user(old_db, u);
free_user(u);
log_it(fname, getpid(), "RELOAD", tabname);
}
u = load_user(crontab_fd, pw, fname);
if (u != NULL) {
u->mtime = statbuf->st_mtime;
if (TargetTime != 0) {
now = time(NULL);
for (e = u->crontab; e != NULL; e = e->next) {
if ((e->flags & INTERVAL) != 0)
e->lastexit = now;
}
}
link_user(new_db, u);
}
next_crontab:
if (crontab_fd >= OK) {
Debug(DLOAD, (" [done]\n"))
close(crontab_fd);
}
}