#if !defined(lint) && !defined(LINT)
static const char rcsid[] =
"$FreeBSD: src/usr.sbin/cron/cron/database.c,v 1.8 1999/08/28 01:15:50 peter Exp $";
#endif
#include "cron.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/file.h>
#define TMAX(a,b) ((a)>(b)?(a):(b))
static void process_crontab __P((char *, char *, char *,
struct stat *,
cron_db *, cron_db *));
void
load_database(old_db)
cron_db *old_db;
{
DIR *dir;
struct stat statbuf;
struct stat syscron_stat;
DIR_T *dp;
cron_db new_db;
user *u, *nu;
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;
if (old_db->mtime == TMAX(statbuf.st_mtime, syscron_stat.st_mtime)) {
Debug(DLOAD, ("[%d] spool dir mtime unch, no load needed.\n",
getpid()))
return;
}
new_db.mtime = TMAX(statbuf.st_mtime, syscron_stat.st_mtime);
new_db.head = new_db.tail = NULL;
if (syscron_stat.st_mtime) {
process_crontab("root", "*system*",
SYSCRONTAB, &syscron_stat,
&new_db, old_db);
}
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';
(void) snprintf(tabname, sizeof tabname, CRON_TAB(fname));
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(db, u)
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(db, u)
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(db, name)
cron_db *db;
char *name;
{
char *env_get();
user *u;
for (u = db->head; u != NULL; u = u->next)
if (!strcmp(u->name, name))
break;
return u;
}
static void
process_crontab(uname, fname, tabname, statbuf, new_db, old_db)
char *uname;
char *fname;
char *tabname;
struct stat *statbuf;
cron_db *new_db;
cron_db *old_db;
{
struct passwd *pw = NULL;
int crontab_fd = OK - 1;
user *u;
if (strcmp(fname, "*system*") && !(pw = getpwnam(uname))) {
log_it(fname, getpid(), "ORPHAN", "no passwd entry");
new_db->mtime = 0; 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;
link_user(new_db, u);
}
next_crontab:
if (crontab_fd >= OK) {
Debug(DLOAD, (" [done]\n"))
close(crontab_fd);
}
}