home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * DCRON.C V1.05
- *
- * Limitations: The only RUN commands allowed are of the form:
- *
- * RUN >nil: <nil: <command>
- *
- * -Wakeup once every minute & check the modify date for S:CRONTAB
- * and to check if the DateStamp() has been re-set.
- *
- * -Attempt to be smart about checking s:crontab (scan the file
- * as little as possible).
- *
- * -Handles massive Date changes and crontab modifications
- *
- * DCRON [-d] logfile
- */
-
- #include <stdio.h>
- #include <local/typedefs.h>
-
- #define CRONTAB "s:crontab"
- #define SIGS (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F)
-
- #define ACTION_READWRITE 1004
- #define ACTION_FIND_INPUT 1005 /* various ACTION's supported */
- #define ACTION_FIND_OUTPUT 1006
- #define ACTION_END 1007
- #define ACTION_EXAMINE 23
- #define ACTION_EXAMINENEXT 24
- #define ACTION_LOCATE 8
- #define ACTION_FREELOCK 15
- #define ACTION_COPYDIR 19
-
- #define DOS_FALSE 0
- #define DOS_TRUE -1
-
- #define BTOC(bptr) ((void *)((long)(bptr) << 2))
-
- typedef struct FileHandle FH;
-
- typedef struct {
- short min;
- short hour;
- short day;
- short month;
- short dow;
- } MHDMW;
-
- typedef struct {
- short entry[5];
- } MHDMWARY;
-
- typedef struct {
- MHDMW Beg;
- MHDMW End;
- } CDATE;
-
- typedef struct {
- char min[60];
- char hour[24];
- char day[32];
- char month[13];
- char dow[7];
- } CARRY;
-
- extern int Enable_Abort;
- extern APTR DeviceProc();
-
- DATESTAMP BegDate; /* Start and end range for */
- DATESTAMP EndDate; /* file compare */
- DATESTAMP ModDate; /* Check if date modified */
- DATESTAMP TabDate; /* Check if crontab modified */
-
- IOT Iot; /* Best guess at next timeout */
- IOT Iotmin; /* 1 minute T.O. (date/file modified test */
- PORT *TPort; /* Collector plate for IO requests */
- short FatalError; /* Uh oh, can't recover */
- short NextTimeout; /* # minutes till next timeout */
- char *LogFile;
- char XDebug;
- long NilFH;
- short CronFileExists = 1; /* Does the crontab file exist? */
-
- void logmessage();
-
- void
- main(ac, av)
- short ac;
- char *av[];
- {
- PROC *proc = FindTask(NULL);
-
- Enable_Abort = 0;
- {
- register short i;
- short j = 0;
-
- for (i = 1; i < ac; ++i) {
- register char *ptr = av[i];
- if (*ptr != '-') {
- switch(j++) {
- case 0:
- LogFile = ptr;
- break;
- }
- continue;
- }
- while (*++ptr) {
- switch(*ptr) {
- case 'd':
- ++XDebug;
- break;
- default:
- WriteStr(Output(), "bad option\n");
- goto fail;
- }
- }
- }
- }
- if (!LogFile) {
- fail:
- WriteStr(Output(), "DCron [-d] Logfile\n");
- WriteStr(Output(), "DCron, V1.05\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 = DeviceProc("NULL:");
- fclose(stderr);
- logmessage("Startup: V1.05 (dist: 22 December 1988)\n");
-
- NilFH = Open("null:", 1006);
- DateStamp(&EndDate);
- DateStamp(&ModDate);
- TPort = CreatePort(NULL,0);
- Iot.tr_time.tv_secs = 1;
- Iot.tr_time.tv_micro= 0;
- Iot.tr_node.io_Message.mn_ReplyPort = TPort;
- Iot.tr_node.io_Command = TR_ADDREQUEST;
- Iotmin = Iot;
- SendIO(&Iot);
- SendIO(&Iotmin);
- 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 scan\n");
- AbortIO(&Iot); /* force execution */
- }
- if (FatalError)
- break;
- if (CheckIO(&Iotmin)) { /* if file/date modified, force exec. */
- WaitIO(&Iotmin);
- if (datemod() + filemod())
- AbortIO(&Iot);
- Iotmin.tr_time.tv_secs = 60;
- Iotmin.tr_time.tv_micro= 0;
- SendIO(&Iotmin);
- }
- if (CheckIO(&Iot)) {
- DATESTAMP Ds;
- short secmin;
-
- WaitIO(&Iot);
- dostuff();
- if (NextTimeout <= 0)
- NextTimeout = 1;
- if (XDebug) {
- logmessage(" Next Timeout in %02ld:%02ld\n",
- NextTimeout / 60,
- NextTimeout % 60
- );
- }
- DateStamp(&Ds);
- secmin = 61 - (Ds.ds_Tick / 50); /* 1+Secs till next min. */
- Iot.tr_time.tv_secs = secmin + (NextTimeout - 1) * 60;
- Iot.tr_time.tv_micro= 0;
- SendIO(&Iot);
- }
- }
- AbortIO(&Iot);
- AbortIO(&Iotmin);
- WaitIO(&Iot);
- WaitIO(&Iotmin);
- CloseDevice(&Iot);
- DeletePort(TPort);
- Close(NilFH);
- }
-
- /*
- * If the current date is less than the previous date
- * If the current date is more than +5 minutes the previous date
- */
-
- datemod()
- {
- DATESTAMP Date;
- long xold, xnew;
-
- DateStamp(&Date);
- xold = ModDate.ds_Days * 1440 + ModDate.ds_Minute;
- xnew = Date.ds_Days * 1440 + Date.ds_Minute;
- ModDate = Date;
- if (xnew < xold || xnew - 5 > xold) {
- DateStamp(&EndDate);
- logmessage("Date change noted\n");
- return(1);
- }
- return(0);
- }
-
- /*
- * If the file modification time is different than when
- * we last checked, we want to recalculate our timeout
- * and rescan it.
- */
-
- filemod()
- {
- char buf[sizeof(FIB)+4];
- register FIB *fib = (FIB *)(((long)buf+3)&~3);
- long lock;
- long result = 0;
-
- if (lock = Lock(CRONTAB, SHARED_LOCK)) {
- if (Examine(lock, fib)) {
- if (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");
- result = 1;
- }
- TabDate = fib->fib_Date;
- }
- }
- UnLock(lock);
- }
- return(result);
- }
-
- /*
- * DOSTUFF()
- *
- * Scan the CRONTAB and execute any entries that fall between
- * BegDate and EndDate. Specifically, >= BegDate and < EndDate.
- *
- * This is done as little as possible. While scanning, we calculate the
- * timeout period till the next entry and will attempt to sleep for that
- * period of time before comming back to this routine. Checks are still
- * done every 60 seconds for radical date changes and crontab modification
- * (routines above).
- *
- * The calculation of the timeout period is not entirely accurate.
- * Specifically, in cases similar to:
- *
- * "30 16 * * *"
- *
- * If the current time is 16:xx, the timeout period calculated for the hours
- * will 0 instead of 24 (if the minutes had been '*', this would be
- * correct. But if it is 16:31 the system will wait 29 minutes instead of
- * 23 hours and 30 minutes. Of course, it will re-scan at +29 minutes and
- * not find anything to do, but you get the point.
- */
-
- static char dim[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
- static CARRY CArry;
- static short CRanStart[] = { 0, 0, 1 , 1, 0 };
- static short CRanEnd[] = { 59, 23, 31 , 12, 6 };
- static long CWeight[] = { 1, 60, 1440, 28*1440, 1440 };
- static char *CBase[] = { CArry.min, CArry.hour, CArry.day, CArry.month, CArry.dow };
-
- dostuff()
- {
- CDATE cdate;
- long fh;
- char buf[256];
- int ie;
-
- NextTimeout = -1;
-
- BegDate = EndDate;
- DateStamp(&EndDate);
- breakup(&EndDate, &cdate.End); /* Breakup the time */
- breakup(&BegDate, &cdate.Beg); /* note: dim[FEB] is modified */
- bzero(&CArry, sizeof(CArry)); /* range array */
-
- /*
- * Generate the range for the delta time that has occured since the
- * last reading. (A) This is used to ensure we don't miss anything
- * (B) Ensure we don't repeat anything
- */
-
- ie = makerange(CArry.min , 0, 59, cdate.Beg.min , cdate.End.min , 1);
- ie = makerange(CArry.hour , 0, 23, cdate.Beg.hour , cdate.End.hour , ie);
- ie = makerange(CArry.day , 1, dim[cdate.Beg.month-1],
- cdate.Beg.day , cdate.End.day , ie);
- ie = makerange(CArry.month, 1, 12, cdate.Beg.month, cdate.End.month, ie);
- ie = makerange(CArry.dow , 0, 6, cdate.Beg.dow , cdate.End.dow , ie);
-
- /*
- * Note: if ie is set after this then dostuff() was called
- * within the same minute segment and would yield a
- * repeation of commands.
- */
-
- if (ie == 0) {
- ReadLn(NULL, NULL, 0);
- if (fh = Open(CRONTAB, 1005)) {
- long whennext; /* in minutes, estimate */
-
- if (CronFileExists == 0) {
- CronFileExists = 1;
- logmessage("DCron File %s exists\n", CRONTAB);
- }
- while (ReadLn(fh, buf, 256)) {
- if (buf[0] == 0 || buf[0] == '#')
- continue;
- whennext = handleline(buf, &cdate.End); /* take smallest */
- if (XDebug > 1)
- logmessage("whennext == %ld\n", whennext);
- if (NextTimeout < 0 || whennext < NextTimeout)
- NextTimeout = whennext;
- }
- Close(fh);
- } else {
- if (CronFileExists == 1) {
- CronFileExists = 0;
- logmessage("Unable to open %s\n", CRONTAB);
- }
- }
- }
-
- /*
- * You can't trust the Amiga's clock vs the timer.device ... this is to
- * ensure that they don't get too far off... no more than an hour timeout
- * is allowed. Frankly, anything above 30 minutes will yield unnoticeable
- * results.
- */
-
- if (--NextTimeout > 60)
- NextTimeout = 60;
- }
-
- breakup(date, mhd)
- DATESTAMP *date;
- MHDMW *mhd;
- {
- 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 < 366); /* is a leap yr*/
- years = 1976 + 4 * years;
- dim[1] = 29;
- if (!leap) {
- dim[1] = 28;
- days -= 366;
- ++years;
- }
- years += days / 365;
- days -= (days / 365) * 365;
- for (month = 0; (month==1) ? (days >= 28 + leap) : (days >= dim[month]); ++month)
- days -= (month==1) ? (28 + leap) : dim[month];
- mhd->min = date->ds_Minute % 60;
- mhd->hour = date->ds_Minute / 60;
- mhd->day = days + 1;
- mhd->month = month + 1;
- mhd->dow = date->ds_Days % 7; /* 0 = sunday */
- }
-
- /*
- * S < RANGE <= E (if previous entries were equal)
- * note: if S == E, E is still included
- * S <= RANGE <= E (if previous entries were not equal)
- */
-
- makerange(ptr, cs, ce, s, e, isequal)
- register char *ptr;
- {
- long error = 5000;
- short oldisequal = isequal;
-
- isequal = (isequal && s == e);
- if (oldisequal && s != e) {
- if (++s > ce)
- s = cs;
- }
- while (--error && s != e) {
- ptr[s++] = 1;
- if (s > ce)
- s = cs;
- }
- ptr[e] = 1;
- if (error == 0) {
- logmessage("DCRON,makerange(): software error\n");
- FatalError = 1;
- }
- return(isequal);
- }
-
- /*
- * This is the core of the routine. The fields are interpreted, times
- * estimated, ready entries run, etc..
- *
- * order: minutes hours days months dayofweek
- *
- * Each field may be a * indicating all-times, and a combination of a
- * range and comma delimited numbers: 0-3,45,46-49 (MUST BE SORTED)
- *
- * Each field is separated by one or spaces+tabs
- */
-
- handleline(buf, endt)
- char *buf;
- MHDMWARY *endt;
- {
- register char *ptr = buf;
- register short i;
- char *gnum();
- short sumok = 0;
- long howsoon = 0; /* how soon until next entry */
-
- for (i = 0; i < 5; ++i) { /* 5 arguments */
- char ok = 0;
- short nextunit = -1; /* count, in units */
-
- while (*ptr == ' ' || *ptr == 9)
- ++ptr;
- while (*ptr && *ptr != 9 && *ptr != ' ') {
- short start;
- short finish;
- if (*ptr == '*') {
- ++ptr;
- ok = 1;
- break;
- }
- ptr = gnum(ptr, &start);
- finish = start;
- if (*ptr == '-')
- ptr = gnum(ptr+1, &finish);
- if (*ptr == ',')
- ++ptr;
-
- /*
- * Determine if current date is within time range. nextunit
- * is the number of time units for this index till the next
- * entry will be executed.
- */
-
- if (endt->entry[i] < start) {
- register short newnextunit = start - endt->entry[i];
- if (nextunit < 0 || newnextunit < nextunit)
- nextunit = newnextunit;
- } else
- if (endt->entry[i] > finish) {
- register short newnextunit = 1 + CRanEnd[i] - endt->entry[i] + start - CRanStart[i];
- if (nextunit < 0 || newnextunit < nextunit)
- nextunit = newnextunit;
- } else
- nextunit = 0; /* Inside time range */
-
- if (start < CRanStart[i] || finish < CRanStart[i] || start > CRanEnd[i] || finish > CRanEnd[i]) {
- logmessage("Illegal Bounds in: %s\n", buf);
- logmessage(" Value %ld & %ld bounds %ld-%ld ", start, finish, CRanStart[i], CRanEnd[i]);
- logmessage(" AT: '%s'\n", ptr);
- continue;
- } else {
- do {
- if (start > CRanEnd[i])
- start = CRanStart[i];
- if (CBase[i][start]) {
- ok = 1;
- break;
- }
- ++start;
- } while (start != finish + 1);
- }
- }
- if (ok)
- ++sumok;
- if (nextunit > 0)
- howsoon += nextunit * CWeight[i];
- }
-
- /*
- * This is tricky. Since this program also handles the dummy-null
- * device, it CANNOT block on the execute. The only way to do that
- * is to run <nil: >nil: so run itself does not attempt to access
- * "*". It is ok if the program run runs accesses "*" as we will not
- * be frozen then.
- */
-
- if (sumok == i) {
- register char *p2 = malloc(strlen(ptr)+32);
-
- logmessage("%s\n", buf);
- while (*ptr == ' ' || *ptr == 9)
- ++ptr;
- /* strcpy(p2, "run <nil: >nil: "); */
- strcpy(p2, "run ");
- strcat(p2, ptr);
- Execute(p2, NilFH, NilFH);
- }
- if (XDebug > 2) {
- logmessage("FOR %-20s In %ld %02ld:%02ld\n",
- buf, howsoon / 1440, howsoon / 60 % 24, howsoon % 60
- );
- }
- return(howsoon);
- }
-
- /*
- * 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;
- MHDMW cb;
- 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);
- breakup(&date, &cb);
-
- sprintf(buf, "dcron: %s %2ld %s %02ld:%02ld ",
- Dow[cb.dow], cb.day, Miy[cb.month], cb.hour, cb.min
- );
- sprintf(buf+strlen(buf), ptr, a, b, c, d, e);
- if ((fh = Open(LogFile, 1005)) == NULL)
- fh = Open(LogFile, 1006);
- if (fh) {
- Seek(fh, 0L, 1);
- WriteStr(fh, buf);
- Close(fh);
- }
- free(buf);
- }
-
- /*
- * Scan a string for a value, return the new pointer position and set the
- * specified short pointer to the value.
- */
-
- char *
- gnum(ptr, pval)
- register char *ptr;
- register short *pval;
- {
- short val = 0;
- if (*ptr < '0' || *ptr > '9')
- logmessage("Not a number: %s\n", ptr);
- while (*ptr >= '0' && *ptr <= '9') {
- val = val * 10 + *ptr - '0';
- ++ptr;
- }
- *pval = val;
- return(ptr);
- }
-
- 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);
- }
-
-