home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / uucp / duucp-1.17 / AU-117b4-src.lha / src / unix / dcron.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-24  |  11.3 KB  |  542 lines

  1. /*
  2. **  DCRON.C  V2
  3. **
  4. **  - loads s:crontab or file crontab specified by -f
  5. **  - checks the datestamp on s:crontab every 60 seconds and reloads the file
  6. **    into memory if changed.
  7. **  - every 60 seconds scans the memory-resident image for things to do
  8. **  - checks for date changes and doesn't reexecute if changes are
  9. **    backwards in time.
  10. **
  11. **  DCRON [-d] [-f crontab] logfile
  12. */
  13.  
  14. #include <exec/types.h>
  15. #include <devices/timer.h>
  16. #include <dos/dos.h>
  17. #include <dos/dosextens.h>
  18.  
  19. /*
  20.  * Needed under SASC for onbreak().  Defined in stdlib under DICE.
  21.  * Must not be included under DICE because it causes conflicts
  22.  * for the definition of getfnl().
  23.  */
  24. #ifdef __SASC
  25. #include <dos.h>
  26. #endif
  27.  
  28. #include <string.h>
  29. #include <stdarg.h>
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #include "config.h"
  33. #include "protos.h"
  34. #include "version.h"
  35.  
  36. IDENT (".02");
  37.  
  38. #define CRONTAB "s:crontab"
  39. #define SIGS    (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F)
  40.  
  41. typedef struct {
  42.     short min;
  43.     short hour;
  44.     short day;
  45.     short month;
  46.     short dow;
  47. } DateAry;
  48.  
  49. typedef struct {
  50.     struct Node myNode;
  51.     UBYTE   BitMap[8][8];   /*    min, hour, day, month, dow */
  52.     char    *Command;
  53. } Command;
  54.  
  55. struct DateStamp
  56.     LastDate,        /*    Date as of last execution    */
  57.     ModDate,        /*    Check if system time  modified    */
  58.     TabDate;        /*    Check if crontab modified    */
  59.  
  60. struct List CmdList;        /*    list of commands        */
  61.  
  62. struct timerequest Iot;
  63. struct MsgPort *TPort;        /*    Collector plate for IO requests     */
  64. char    *LogFile;
  65. char    *CronFile = CRONTAB;
  66. char    XDebug;
  67. BPTR    NilFH;            /*    NIL: file handle            */
  68. short    CronFileExists = 0; /*    -1, 0, 1                */
  69.  
  70. void    logmessage(char *ptr, ...);
  71. void    LoadCronFile (void);
  72. void    LoadBitMap (char **, UBYTE *);
  73. void    WriteStr (BPTR, char *);
  74. void    DRunCommand (char *);
  75. void    ExecuteCommands (short *, short *);
  76. int    CheckDateChanged (void);
  77. void    CheckFileModified (void);
  78. int    ReadLn (BPTR, char *, short);
  79. void    DateToDateAry (struct DateStamp *, DateAry *);
  80.  
  81. int
  82. brk (void)
  83. {
  84.     return 0;
  85. }
  86.  
  87. int
  88. main (int ac, char **av)
  89. {
  90.     struct Process
  91.         *proc = (struct Process *) FindTask (NULL);
  92.     APTR
  93.         oldConsoleTask = proc->pr_ConsoleTask;
  94.  
  95.     onbreak(brk);
  96.     NewList(&CmdList);
  97.  
  98.     {
  99.     register short
  100.         i;
  101.  
  102.     for (i = 1; i < ac; ++i) {
  103.         register char
  104.             *ptr = av [i];
  105.  
  106.         if (*ptr != '-') {
  107.         LogFile = ptr;
  108.         continue;
  109.         }
  110.         while (*++ptr) {
  111.         switch(*ptr) {
  112.         case 'd':
  113.             ++XDebug;
  114.             break;
  115.         case 'f':
  116.             CronFile = av[++i];
  117.             break;
  118.         default:
  119.             WriteStr(Output(), "bad option\n");
  120.             goto fail;
  121.         }
  122.         }
  123.     }
  124.     if (CronFile == NULL) {
  125.         puts("-f : expected filename");
  126.         exit(1);
  127.     }
  128.     }
  129.     if (!LogFile) {
  130. fail:
  131.     WriteStr(Output(), "DCron [-d] [-f cronfile] Logfile\n");
  132.     WriteStr(Output(), "DCron, V2.02\n");
  133.     exit(1);
  134.     }
  135.     if (OpenDevice ((UBYTE *) "timer.device", 0, (struct IORequest *) &Iot, UNIT_VBLANK)) {
  136.     logmessage("Unable to open timer.device\n");
  137.     exit(1);
  138.     }
  139.     if (!DeviceProc ((UBYTE *) "NULL:")) {
  140.     logmessage("NULL: device required for dcron to run\n");
  141.     WriteStr(Output(), "NULL: device required to run\n");
  142.     exit(1);
  143.     }
  144.     proc->pr_ConsoleTask = (APTR) DeviceProc ((UBYTE *) "NULL:");
  145.     fclose(stderr);
  146.  
  147.     logmessage("Startup: V2.02 (dist: 15 Dec 1993)\n");
  148.  
  149.     NilFH = Open ((UBYTE *) "null:", 1006);
  150.     DateStamp(&LastDate);
  151.     DateStamp(&ModDate);
  152.     TPort = (struct MsgPort *) CreatePort (NULL, 0);
  153.     printf("RESULT %08lx\n", TPort);
  154.     Iot.tr_time.tv_secs = 2;
  155.     Iot.tr_time.tv_micro= 0;
  156.     Iot.tr_node.io_Message.mn_ReplyPort = TPort;
  157.     Iot.tr_node.io_Command = TR_ADDREQUEST;
  158.     SendIO ((struct IORequest *) &Iot);    /*  timeout */
  159.  
  160.     for (;;) {
  161.     long mask;
  162.  
  163.     mask = Wait(SIGS | (1 << TPort->mp_SigBit));
  164.     if (mask & (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)) {
  165.         logmessage("DCRON: Break\n");
  166.         break;
  167.     }
  168.     if (mask & (SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F)) {
  169.         logmessage ("^E/F force check\n");
  170.         AbortIO ((struct IORequest *) &Iot); /*  force execution */
  171.     }
  172.     if (CheckIO ((struct IORequest *) &Iot)) { /*  if file/date modified, force exec.  */
  173.         struct DateStamp Ds;
  174.         DateAry D1, D2;
  175.         int st;
  176.  
  177.         WaitIO ((struct IORequest *) &Iot);
  178.         st = CheckDateChanged();
  179.         CheckFileModified();
  180.         DateStamp(&Ds);
  181.         DateToDateAry(&LastDate, &D1);
  182.         DateToDateAry(&Ds, &D2);
  183.         if (st == 0)
  184.         ExecuteCommands ((short *) &D1, (short *) &D2);
  185.         LastDate = Ds;
  186.         DateStamp(&Ds);
  187.         Iot.tr_time.tv_secs = 61 - Ds.ds_Tick / 50;
  188.         Iot.tr_time.tv_micro= 0;
  189.         SendIO ((struct IORequest *) &Iot);
  190.     }
  191.     }
  192.     AbortIO ((struct IORequest *) &Iot);
  193.     WaitIO ((struct IORequest *) &Iot);
  194.     CloseDevice ((struct IORequest *) &Iot);
  195.     DeletePort(TPort);
  196.     Close(NilFH);
  197.     proc->pr_ConsoleTask = oldConsoleTask;
  198. }
  199.  
  200. /*
  201.  *  Returns 0 = execute objects for range
  202.  *        1 = do not execute objects for range
  203.  */
  204.  
  205. int
  206. CheckDateChanged (void)
  207. {
  208.     struct DateStamp Ds;
  209.     long xold, xnew;
  210.     static char state = 0;
  211.  
  212.     DateStamp(&Ds);
  213.     xold = ModDate.ds_Days * 1440 + ModDate.ds_Minute;
  214.     xnew = Ds.ds_Days * 1440 + Ds.ds_Minute;
  215.  
  216.     /*
  217.      *    if backwards or more than T+5min
  218.      */
  219.  
  220.     if (xnew < xold || xnew - 5 > xold) {
  221.     DateStamp(&LastDate);
  222.     if (state == 0)
  223.         logmessage("Date change noted, %d mins\n", xnew - xold + 1);
  224.     state = 1;
  225.     } else {
  226.     state = 0;
  227.     }
  228.  
  229.     /*
  230.      *    If all is ok or too far away from old date then set new base
  231.      *    date for next comparison (T +/- 10min)
  232.      */
  233.  
  234.     if (state == 0 || xold - xnew > 10 || xold - xnew < -10 ) {
  235.     ModDate = Ds;
  236.     }
  237.     return((int)state);
  238. }
  239.  
  240. void
  241. CheckFileModified (void)
  242. {
  243.     char buf [sizeof (struct FileInfoBlock) + 4];
  244.     BPTR lock;
  245.  
  246.     if (lock = Lock ((UBYTE *) CronFile, SHARED_LOCK)) {
  247.     register struct FileInfoBlock *fib = (struct FileInfoBlock *)(((long)buf+3)&~3);
  248.     if (Examine(lock, fib)) {
  249.         if (CronFileExists < 1 ||
  250.         fib->fib_Date.ds_Tick    != TabDate.ds_Tick ||
  251.         fib->fib_Date.ds_Minute != TabDate.ds_Minute ||
  252.         fib->fib_Date.ds_Days    != TabDate.ds_Days)
  253.         {
  254.         if (TabDate.ds_Days) {
  255.             logmessage("crontab modification noted\n");
  256.         }
  257.         TabDate = fib->fib_Date;
  258.         LoadCronFile();
  259.         }
  260.     }
  261.     UnLock(lock);
  262.     } else {
  263.     if (CronFileExists >= 0) {
  264.         logmessage("unable to lock cronfile %s!\n", CronFile);
  265.         CronFileExists = -1;
  266.     }
  267.     }
  268. }
  269.  
  270. /*
  271.  *  execute commands that fall d1 < cmd <= d2
  272.  */
  273.  
  274. void
  275. ExecuteCommands(short *d1, short *d2) /* min, hour, day, month, dow */
  276. {
  277.     Command *cmd;
  278.     struct Node *nd;
  279.     short i;
  280.     short n;
  281.  
  282.     for (nd = GetHead(&CmdList); nd; nd = GetSucc(&cmd->myNode)) {
  283.     short ok = 1;
  284.  
  285.     cmd = (Command *)nd;
  286.  
  287.     for (i = 0; i < 5; ++i) {
  288.         UBYTE *bitmap = cmd->BitMap[i];
  289.  
  290.         n = d2[i];
  291.         if (n == d1[i]) {
  292.         if ((bitmap[n>>3] & (1 << (n & 7))) == 0) {
  293.             ok = 0;
  294.             break;
  295.         }
  296.         } else {
  297.         while (n != d1[i]) {
  298.             if (bitmap[n>>3] & (1 << (n & 7)))
  299.             break;
  300.             n = (n - 1) & 63;
  301.         }
  302.         if (n == d1[i]) {
  303.             ok = 0;
  304.             break;
  305.         }
  306.         }
  307.     }
  308.     if (ok)
  309.         DRunCommand(cmd->Command);
  310.     }
  311. }
  312.  
  313. void
  314. DRunCommand(char *cmd)
  315. {
  316.     char buf[256];
  317.  
  318.     logmessage("%s\n", cmd);
  319.     strcpy(buf, "run ");
  320.     strcat(buf, cmd);
  321.     Execute ((UBYTE *) buf, NilFH, NilFH);
  322. }
  323.  
  324. void
  325. DateToDateAry (struct DateStamp *date, DateAry *da)
  326. {
  327.     static char dim[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  328.     long days;
  329.     long years;
  330.     char leap;
  331.     short month;
  332.  
  333.     days = date->ds_Days + 731;         /*    1976        */
  334.     years = days / (365*3+366);         /*    #quad yrs   */
  335.     days -= years * (365*3+366);
  336.     leap = (days <= 365);            /*    is a leap yr*/
  337.     years = 1976 + 4 * years;
  338.     dim[1] = 29;
  339.     if (leap == 0) {
  340.     dim[1] = 28;
  341.     days -= 366;
  342.     ++years;
  343.     years += days / 365;
  344.     days %= 365;
  345.     }
  346.     for (month = 0; (month==1) ? (days >= 28 + leap) : (days >= dim[month]); ++month)
  347.     days -= (month==1) ? (28 + leap) : dim[month];
  348.  
  349.     da->min    = date->ds_Minute % 60;
  350.     da->hour   = date->ds_Minute / 60;
  351.     da->day    = days + 1;
  352.     da->month  = month + 1;
  353.     da->dow    = date->ds_Days % 7;    /*  0 = sunday    */
  354. }
  355.  
  356. void
  357. LoadCronFile (void)
  358. {
  359.     char buf[256];
  360.     BPTR fh;
  361.     Command *cmd;
  362.  
  363.     while (cmd = (Command *)RemHead(&CmdList))
  364.     free(cmd);
  365.  
  366.     ReadLn(0, 0, 0);
  367.     fh = Open ((UBYTE *) CronFile, 1005);
  368.     if (fh == NULL) {
  369.     if (CronFileExists != -1)
  370.         logmessage("unable to open cronfile %s!\n", CronFile);
  371.     CronFileExists = -1;
  372.     return;
  373.     }
  374.     while (ReadLn(fh, buf, 256)) {
  375.     char *ptr = buf;
  376.     short i;
  377.  
  378.     if (buf[0] == 0 || buf[0] == '#')
  379.         continue;
  380.     cmd = (Command *)malloc(sizeof(Command));
  381.     setmem(cmd, sizeof(Command), 0);
  382.  
  383.     for (i = 0; i < 5; ++i) {        /*  5 time fields   */
  384.         /*
  385.         printf("lb %d\n", i);
  386.         */
  387.         LoadBitMap(&ptr, cmd->BitMap[i]);
  388.     }
  389.  
  390.     while (*ptr == ' ' || *ptr == 9)
  391.         ++ptr;
  392.     cmd->Command = malloc(strlen(ptr) + 1);
  393.     strcpy(cmd->Command, ptr);
  394.  
  395.     /*
  396.     for (i = 0; i < 5; ++i) {
  397.         for (j = 0; j < 4; ++j)
  398.         printf("%02x", cmd->BitMap[i][j]);
  399.         printf(" ");
  400.         for (j = 4; j < 8; ++j)
  401.         printf("%02x", cmd->BitMap[i][j]);
  402.         puts("");
  403.     }
  404.  
  405.     printf("cmd = %s\n", cmd->Command);
  406.     */
  407.  
  408.     AddTail(&CmdList, &cmd->myNode);
  409.     }
  410.     Close(fh);
  411.     CronFileExists = 1;
  412. }
  413.  
  414. void
  415. LoadBitMap(char **pptr, UBYTE *bm)
  416.             /*  8 bytes = 64 entries    */
  417. {
  418.     register char *ptr = *pptr;
  419.  
  420.     while (*ptr == ' ' || *ptr == 9)
  421.     ++ptr;
  422.  
  423.     /*
  424.      *    looking for *, number range n-n, single numbers, etc...  1,2,8-10 ...
  425.      */
  426.  
  427.     while (*ptr == '*' || (*ptr >= '0' && *ptr <= '9')) {
  428.     short v1, v2;
  429.  
  430.     v1 = 0;
  431.     while (*ptr >= '0' && *ptr <= '9') {
  432.         v1 = v1 * 10 + *ptr - '0';
  433.         ++ptr;
  434.     }
  435.     if (*ptr == '-') {
  436.         ++ptr;
  437.         v2 = 0;
  438.         while (*ptr >= '0' && *ptr <= '9') {
  439.         v2 = v2 * 10 + *ptr - '0';
  440.         ++ptr;
  441.         }
  442.     } else {
  443.         v2 = v1;
  444.     }
  445.     if (*ptr == '*') {
  446.         v1 = 0;
  447.         v2 = 63;
  448.         ++ptr;
  449.     }
  450.     if (v1 < 0)
  451.         v1 = 0;
  452.     if (v1 > 63)
  453.         v1 = 63;
  454.     if (v2 < 0)
  455.         v2 = 0;
  456.     if (v2 > 63)
  457.         v2 = 63;
  458.  
  459.     --v1;
  460.     do {
  461.         v1 = (v1 + 1) & 63;
  462.         bm[v1>>3] |= (1 << (v1 & 7));
  463.     } while (v1 != v2);
  464.     if (*ptr == ',')
  465.         ++ptr;
  466.     }
  467.     *pptr = ptr;
  468. }
  469.  
  470. /*
  471.  *  Poor man's log.  Note that the log file is not left open ... this allows
  472.  *  one to read or tail it at any time.
  473.  */
  474.  
  475. void
  476. logmessage(char *ptr, ...)
  477. {
  478.     char *buf = malloc(512);
  479.     struct DateStamp date;
  480.     DateAry da;
  481.     BPTR fh;
  482.     va_list ap;
  483.     static char *Dow[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
  484.     static char *Miy[] = { "---", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  485.                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
  486.  
  487.     if (!buf)
  488.     return;
  489.  
  490.     DateStamp(&date);
  491.     DateToDateAry(&date, &da);
  492.  
  493.     sprintf(buf, "dcron: %s %2ld %s %02ld:%02ld   ",
  494.     Dow[da.dow], da.day, Miy[da.month], da.hour, da.min
  495.     );
  496.  
  497.     va_start(ap, ptr);
  498.     vsprintf(buf+strlen(buf), ptr, ap);
  499.     va_end(ap);
  500.  
  501.     if ((fh = Open ((UBYTE *) LogFile, 1005)) == 0)
  502.     fh  = Open ((UBYTE *) LogFile, 1006);
  503.     if (fh) {
  504.     Seek(fh, 0L, 1);
  505.     WriteStr(fh, buf);
  506.     Close(fh);
  507.     }
  508.     free(buf);
  509. }
  510.  
  511. void
  512. WriteStr (BPTR fh, char *buf)
  513. {
  514.     Write(fh, buf, strlen (buf));
  515. }
  516.  
  517. int ReadLn (BPTR fh, char *buf, short max)
  518. {
  519.     static char Data[1024];
  520.     static short RIdx, RLen;
  521.     register short i;
  522.  
  523.     if (fh == NULL) {
  524.     RIdx = RLen = 0;
  525.     return(0);
  526.     }
  527.     for (--max, i = 0; i < max; ++i) {
  528.     if (RIdx == RLen) {
  529.         RLen = Read(fh, Data, 1024);
  530.         RIdx = 0;
  531.         if (RLen <= 0) {
  532.         buf[i] = 0;
  533.         return(0);
  534.         }
  535.     }
  536.     if ((buf[i] = Data[RIdx++]) == '\n')
  537.         break;
  538.     }
  539.     buf[i] = 0;
  540.     return(1);
  541. }
  542.