home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
fish
/
telecom
/
uucp_442
/
src
/
unix
/
dcron.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-05-29
|
11KB
|
535 lines
/*
* DCRON.C V2
*
* - loads s:crontab or file crontab specified by -f
* - checks the datestamp on s:crontab every 60 seconds and reloads the file
* into memory if changed.
* - every 60 seconds scans the memory-resident image for things to do
* - checks for date changes and doesn't reexecute if changes are
* backwards in time.
*
* DCRON [-d] [-f crontab] logfile
*/
#include <exec/types.h>
#include <devices/timer.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <stdio.h>
#include "protos.h"
typedef struct Node NODE;
typedef struct List LIST;
typedef struct DateStamp DATESTAMP;
typedef struct timerequest IOT;
typedef struct MsgPort PORT;
typedef struct Process PROC;
typedef struct FileInfoBlock FIB;
#define CRONTAB "s:crontab"
#define SIGS (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F)
typedef struct {
short min;
short hour;
short day;
short month;
short dow;
} DateAry;
typedef struct {
NODE Node;
UBYTE BitMap[8][8]; /* min, hour, day, month, dow */
char *Command;
} Command;
extern char *malloc();
DATESTAMP LastDate; /* Date as of last execution */
DATESTAMP ModDate; /* Check if system time modified */
DATESTAMP TabDate; /* Check if crontab modified */
LIST CmdList; /* list of commands */
IOT Iot;
PORT *TPort; /* Collector plate for IO requests */
short FatalError; /* Uh oh, can't recover */
char *LogFile;
char *CronFile = CRONTAB;
char XDebug;
long NilFH; /* NIL: file handle */
short CronFileExists = 0; /* -1, 0, 1 */
void logmessage();
void LoadCronFile();
void LoadBitMap();
void WriteStr();
void RunCommand();
void ExecuteCommands();
void CheckFileModified();
void DateToDateAry();
void *GetHead();
void *GetSucc();
int
brk()
{
return(0);
}
void
main(ac, av)
short ac;
char *av[];
{
PROC *proc = (PROC *)FindTask(NULL);
APTR oldConsoleTask = proc->pr_ConsoleTask;
onbreak(brk);
NewList(&CmdList);
{
register short i;
for (i = 1; i < ac; ++i) {
register char *ptr = av[i];
if (*ptr != '-') {
LogFile = ptr;
continue;
}
while (*++ptr) {
switch(*ptr) {
case 'd':
++XDebug;
break;
case 'f':
CronFile = av[++i];
break;
default:
WriteStr(Output(), "bad option\n");
goto fail;
}
}
}
if (CronFile == NULL) {
puts("-f : expected filename");
exit(1);
}
}
if (!LogFile) {
fail:
WriteStr(Output(), "DCron [-d] [-f cronfile] Logfile\n");
WriteStr(Output(), "DCron, V2.02\n");
exit(1);
}
if (OpenDevice("timer.device", 0, &Iot, UNIT_VBLANK)) {
logmessage("Unable to open timer.device\n");
exit(1);
}
if (!DeviceProc("NULL:")) {
logmessage("NULL: device required for dcron to run\n");
WriteStr(Output(), "NULL: device required to run\n");
exit(1);
}
proc->pr_ConsoleTask = (APTR)DeviceProc("NULL:");
fclose(stderr);
logmessage("Startup: V2.02 (dist: 29 May 1990)\n");
NilFH = (long)Open("null:", 1006);
DateStamp(&LastDate);
DateStamp(&ModDate);
TPort = CreatePort(NULL,0);
Iot.tr_time.tv_secs = 2;
Iot.tr_time.tv_micro= 0;
Iot.tr_node.io_Message.mn_ReplyPort = TPort;
Iot.tr_node.io_Command = TR_ADDREQUEST;
SendIO(&Iot); /* timeout */
for (;;) {
long mask;
mask = Wait(SIGS | (1 << TPort->mp_SigBit));
if (mask & (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)) {
logmessage("DCRON: Break\n");
break;
}
if (mask & (SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F)) {
logmessage("^E/F force check\n");
AbortIO(&Iot); /* force execution */
}
if (FatalError)
break;
if (CheckIO(&Iot)) { /* if file/date modified, force exec. */
DATESTAMP Ds;
DateAry D1, D2;
int st;
WaitIO(&Iot);
st = CheckDateChanged();
CheckFileModified();
DateStamp(&Ds);
DateToDateAry(&LastDate, &D1);
DateToDateAry(&Ds, &D2);
if (st == 0)
ExecuteCommands(&D1, &D2);
LastDate = Ds;
DateStamp(&Ds);
Iot.tr_time.tv_secs = 61 - Ds.ds_Tick / 50;
Iot.tr_time.tv_micro= 0;
SendIO(&Iot);
}
}
AbortIO(&Iot);
WaitIO(&Iot);
CloseDevice(&Iot);
DeletePort(TPort);
Close(NilFH);
proc->pr_ConsoleTask = oldConsoleTask;
}
/*
* Returns 0 = execute objects for range
* 1 = do not execute objects for range
*/
CheckDateChanged()
{
DATESTAMP Ds;
long xold, xnew;
static char state = 0;
DateStamp(&Ds);
xold = ModDate.ds_Days * 1440 + ModDate.ds_Minute;
xnew = Ds.ds_Days * 1440 + Ds.ds_Minute;
/*
* if backwards or more than T+5min
*/
if (xnew < xold || xnew - 5 > xold) {
DateStamp(&LastDate);
if (state == 0)
logmessage("Date change noted, %d mins\n", xnew - xold + 1);
state = 1;
} else {
state = 0;
}
/*
* If all is ok or too far away from old date then set new base
* date for next comparison (T +/- 10min)
*/
if (state == 0 || xold - xnew > 10 || xold - xnew < -10 ) {
ModDate = Ds;
}
return((int)state);
}
void
CheckFileModified()
{
char buf[sizeof(FIB)+4];
long lock;
if (lock = (long)Lock(CronFile, SHARED_LOCK)) {
register FIB *fib = (FIB *)(((long)buf+3)&~3);
if (Examine(lock, fib)) {
if (CronFileExists < 1 ||
fib->fib_Date.ds_Tick != TabDate.ds_Tick ||
fib->fib_Date.ds_Minute != TabDate.ds_Minute ||
fib->fib_Date.ds_Days != TabDate.ds_Days)
{
if (TabDate.ds_Days) {
logmessage("crontab modification noted\n");
}
TabDate = fib->fib_Date;
LoadCronFile();
}
}
UnLock(lock);
} else {
if (CronFileExists >= 0) {
logmessage("unable to lock cronfile %s!\n", CronFile);
CronFileExists = -1;
}
}
}
/*
* execute commands that fall d1 < cmd <= d2
*/
void
ExecuteCommands(d1, d2)
short *d1, *d2; /* min, hour, day, month, dow */
{
Command *cmd;
short i;
short n;
for (cmd = GetHead(&CmdList); cmd; cmd = GetSucc(&cmd->Node)) {
short ok = 1;
for (i = 0; i < 5; ++i) {
UBYTE *bitmap = cmd->BitMap[i];
n = d2[i];
if (n == d1[i]) {
if ((bitmap[n>>3] & (1 << (n & 7))) == 0) {
ok = 0;
break;
}
} else {
while (n != d1[i]) {
if (bitmap[n>>3] & (1 << (n & 7)))
break;
n = (n - 1) & 63;
}
if (n == d1[i]) {
ok = 0;
break;
}
}
}
if (ok)
RunCommand(cmd->Command);
}
}
void
RunCommand(cmd)
char *cmd;
{
char buf[256];
logmessage("%s\n", cmd);
strcpy(buf, "run ");
strcat(buf, cmd);
Execute(buf, NilFH, NilFH);
}
void
DateToDateAry(date, da)
DATESTAMP *date;
DateAry *da;
{
static char dim[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
long days;
long years;
char leap;
short month;
days = date->ds_Days + 731; /* 1976 */
years = days / (365*3+366); /* #quad yrs */
days -= years * (365*3+366);
leap = (days <= 365); /* is a leap yr*/
years = 1976 + 4 * years;
dim[1] = 29;
if (leap == 0) {
dim[1] = 28;
days -= 366;
++years;
years += days / 365;
days %= 365;
}
for (month = 0; (month==1) ? (days >= 28 + leap) : (days >= dim[month]); ++month)
days -= (month==1) ? (28 + leap) : dim[month];
da->min = date->ds_Minute % 60;
da->hour = date->ds_Minute / 60;
da->day = days + 1;
da->month = month + 1;
da->dow = date->ds_Days % 7; /* 0 = sunday */
}
void
LoadCronFile()
{
char buf[256];
long fh;
Command *cmd;
while (cmd = (Command *)RemHead(&CmdList))
free(cmd);
ReadLn(NULL, NULL, 0);
fh = (long)Open(CronFile, 1005);
if (fh == NULL) {
if (CronFileExists != -1)
logmessage("unable to open cronfile %s!\n", CronFile);
CronFileExists = -1;
return;
}
while (ReadLn(fh, buf, 256)) {
char *ptr = buf;
short i;
if (buf[0] == 0 || buf[0] == '#')
continue;
cmd = (Command *)malloc(sizeof(Command));
setmem(cmd, sizeof(Command), 0);
for (i = 0; i < 5; ++i) { /* 5 time fields */
/*
printf("lb %d\n", i);
*/
LoadBitMap(&ptr, cmd->BitMap[i]);
}
while (*ptr == ' ' || *ptr == 9)
++ptr;
cmd->Command = malloc(strlen(ptr) + 1);
strcpy(cmd->Command, ptr);
/*
for (i = 0; i < 5; ++i) {
for (j = 0; j < 4; ++j)
printf("%02x", cmd->BitMap[i][j]);
printf(" ");
for (j = 4; j < 8; ++j)
printf("%02x", cmd->BitMap[i][j]);
puts("");
}
printf("cmd = %s\n", cmd->Command);
*/
AddTail(&CmdList, &cmd->Node);
}
Close(fh);
CronFileExists = 1;
}
void
LoadBitMap(pptr, bm)
char **pptr;
UBYTE *bm; /* 8 bytes = 64 entries */
{
register char *ptr = *pptr;
while (*ptr == ' ' || *ptr == 9)
++ptr;
/*
* looking for *, number range n-n, single numbers, etc... 1,2,8-10 ...
*/
while (*ptr == '*' || (*ptr >= '0' && *ptr <= '9')) {
short v1, v2;
v1 = 0;
while (*ptr >= '0' && *ptr <= '9') {
v1 = v1 * 10 + *ptr - '0';
++ptr;
}
if (*ptr == '-') {
++ptr;
v2 = 0;
while (*ptr >= '0' && *ptr <= '9') {
v2 = v2 * 10 + *ptr - '0';
++ptr;
}
} else {
v2 = v1;
}
if (*ptr == '*') {
v1 = 0;
v2 = 63;
++ptr;
}
if (v1 < 0)
v1 = 0;
if (v1 > 63)
v1 = 63;
if (v2 < 0)
v2 = 0;
if (v2 > 63)
v2 = 63;
--v1;
do {
v1 = (v1 + 1) & 63;
bm[v1>>3] |= (1 << (v1 & 7));
} while (v1 != v2);
if (*ptr == ',')
++ptr;
}
*pptr = ptr;
}
/*
* Poor man's log. Note that the log file is not left open ... this allows
* one to read or tail it at any time.
*/
void
logmessage(ptr, a, b, c, d, e)
char *ptr;
{
char *buf = malloc(512);
DATESTAMP date;
DateAry da;
long fh;
static char *Dow[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
static char *Miy[] = { "---", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
if (!buf)
return;
DateStamp(&date);
DateToDateAry(&date, &da);
sprintf(buf, "dcron: %s %2ld %s %02ld:%02ld ",
Dow[da.dow], da.day, Miy[da.month], da.hour, da.min
);
sprintf(buf+strlen(buf), ptr, a, b, c, d, e);
if ((fh = (long)Open(LogFile, 1005)) == NULL)
fh = (long)Open(LogFile, 1006);
if (fh) {
Seek(fh, 0L, 1);
WriteStr(fh, buf);
Close(fh);
}
free(buf);
}
void
WriteStr(fh, buf)
long fh;
char *buf;
{
Write(fh, buf, strlen(buf));
}
ReadLn(fh, buf, max)
long fh;
char *buf;
short max;
{
static char Data[1024];
static short RIdx, RLen;
register short i;
if (fh == NULL) {
RIdx = RLen = 0;
return(0);
}
for (--max, i = 0; i < max; ++i) {
if (RIdx == RLen) {
RLen = Read(fh, Data, 1024);
RIdx = 0;
if (RLen <= 0) {
buf[i] = 0;
return(0);
}
}
if ((buf[i] = Data[RIdx++]) == '\n')
break;
}
buf[i] = 0;
return(1);
}