home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 4 / CDPD_IV.bin / networking / uucp / amigauucpsrc / unix / dcron.c < prev    next >
C/C++ Source or Header  |  1994-06-29  |  11KB  |  536 lines

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