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 >
C/C++ Source or Header  |  1990-05-29  |  11KB  |  535 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    RunCommand();
  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.     Iot.tr_time.tv_secs = 2;
  145.     Iot.tr_time.tv_micro= 0;
  146.     Iot.tr_node.io_Message.mn_ReplyPort = TPort;
  147.     Iot.tr_node.io_Command = TR_ADDREQUEST;
  148.     SendIO(&Iot);                                   /*  timeout */
  149.  
  150.     for (;;) {
  151.     long mask;
  152.     mask = Wait(SIGS | (1 << TPort->mp_SigBit));
  153.     if (mask & (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)) {
  154.         logmessage("DCRON: Break\n");
  155.         break;
  156.     }
  157.     if (mask & (SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F)) {
  158.         logmessage("^E/F force check\n");
  159.         AbortIO(&Iot);          /*  force execution                     */
  160.     }
  161.     if (FatalError)
  162.         break;
  163.     if (CheckIO(&Iot)) {        /*  if file/date modified, force exec.  */
  164.         DATESTAMP Ds;
  165.         DateAry D1, D2;
  166.         int st;
  167.  
  168.         WaitIO(&Iot);
  169.         st = CheckDateChanged();
  170.         CheckFileModified();
  171.         DateStamp(&Ds);
  172.         DateToDateAry(&LastDate, &D1);
  173.         DateToDateAry(&Ds, &D2);
  174.         if (st == 0)
  175.         ExecuteCommands(&D1, &D2);
  176.         LastDate = Ds;
  177.         DateStamp(&Ds);
  178.         Iot.tr_time.tv_secs = 61 - Ds.ds_Tick / 50;
  179.         Iot.tr_time.tv_micro= 0;
  180.         SendIO(&Iot);
  181.     }
  182.     }
  183.     AbortIO(&Iot);
  184.     WaitIO(&Iot);
  185.     CloseDevice(&Iot);
  186.     DeletePort(TPort);
  187.     Close(NilFH);
  188.     proc->pr_ConsoleTask = oldConsoleTask;
  189. }
  190.  
  191. /*
  192.  *  Returns 0 = execute objects for range
  193.  *        1 = do not execute objects for range
  194.  */
  195.  
  196. CheckDateChanged()
  197. {
  198.     DATESTAMP Ds;
  199.     long xold, xnew;
  200.     static char state = 0;
  201.  
  202.     DateStamp(&Ds);
  203.     xold = ModDate.ds_Days * 1440 + ModDate.ds_Minute;
  204.     xnew = Ds.ds_Days * 1440 + Ds.ds_Minute;
  205.  
  206.     /*
  207.      *    if backwards or more than T+5min
  208.      */
  209.  
  210.     if (xnew < xold || xnew - 5 > xold) {
  211.     DateStamp(&LastDate);
  212.     if (state == 0)
  213.         logmessage("Date change noted, %d mins\n", xnew - xold + 1);
  214.     state = 1;
  215.     } else {
  216.     state = 0;
  217.     }
  218.  
  219.     /*
  220.      *    If all is ok or too far away from old date then set new base
  221.      *    date for next comparison (T +/- 10min)
  222.      */
  223.  
  224.     if (state == 0 || xold - xnew > 10 || xold - xnew < -10 ) {
  225.     ModDate = Ds;
  226.     }
  227.     return((int)state);
  228. }
  229.  
  230. void
  231. CheckFileModified()
  232. {
  233.     char buf[sizeof(FIB)+4];
  234.     long lock;
  235.  
  236.     if (lock = (long)Lock(CronFile, SHARED_LOCK)) {
  237.     register FIB *fib = (FIB *)(((long)buf+3)&~3);
  238.     if (Examine(lock, fib)) {
  239.         if (CronFileExists < 1 ||
  240.         fib->fib_Date.ds_Tick    != TabDate.ds_Tick ||
  241.         fib->fib_Date.ds_Minute != TabDate.ds_Minute ||
  242.         fib->fib_Date.ds_Days    != TabDate.ds_Days)
  243.         {
  244.         if (TabDate.ds_Days) {
  245.             logmessage("crontab modification noted\n");
  246.         }
  247.         TabDate = fib->fib_Date;
  248.         LoadCronFile();
  249.         }
  250.     }
  251.     UnLock(lock);
  252.     } else {
  253.     if (CronFileExists >= 0) {
  254.         logmessage("unable to lock cronfile %s!\n", CronFile);
  255.         CronFileExists = -1;
  256.     }
  257.     }
  258. }
  259.  
  260. /*
  261.  *  execute commands that fall d1 < cmd <= d2
  262.  */
  263.  
  264. void
  265. ExecuteCommands(d1, d2)
  266. short *d1, *d2;     /*    min, hour, day, month, dow  */
  267. {
  268.     Command *cmd;
  269.     short i;
  270.     short n;
  271.  
  272.     for (cmd = GetHead(&CmdList); cmd; cmd = GetSucc(&cmd->Node)) {
  273.     short ok = 1;
  274.     for (i = 0; i < 5; ++i) {
  275.         UBYTE *bitmap = cmd->BitMap[i];
  276.  
  277.         n = d2[i];
  278.         if (n == d1[i]) {
  279.         if ((bitmap[n>>3] & (1 << (n & 7))) == 0) {
  280.             ok = 0;
  281.             break;
  282.         }
  283.         } else {
  284.         while (n != d1[i]) {
  285.             if (bitmap[n>>3] & (1 << (n & 7)))
  286.             break;
  287.             n = (n - 1) & 63;
  288.         }
  289.         if (n == d1[i]) {
  290.             ok = 0;
  291.             break;
  292.         }
  293.         }
  294.     }
  295.     if (ok)
  296.         RunCommand(cmd->Command);
  297.     }
  298. }
  299.  
  300. void
  301. RunCommand(cmd)
  302. char *cmd;
  303. {
  304.     char buf[256];
  305.  
  306.     logmessage("%s\n", cmd);
  307.     strcpy(buf, "run ");
  308.     strcat(buf, cmd);
  309.     Execute(buf, NilFH, NilFH);
  310. }
  311.  
  312. void
  313. DateToDateAry(date, da)
  314. DATESTAMP *date;
  315. DateAry *da;
  316. {
  317.     static char dim[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  318.     long days;
  319.     long years;
  320.     char leap;
  321.     short month;
  322.  
  323.     days = date->ds_Days + 731;         /*    1976        */
  324.     years = days / (365*3+366);             /*  #quad yrs   */
  325.     days -= years * (365*3+366);
  326.     leap = (days <= 365);                   /*  is a leap yr*/
  327.     years = 1976 + 4 * years;
  328.     dim[1] = 29;
  329.     if (leap == 0) {
  330.     dim[1] = 28;
  331.     days -= 366;
  332.     ++years;
  333.     years += days / 365;
  334.     days %= 365;
  335.     }
  336.     for (month = 0; (month==1) ? (days >= 28 + leap) : (days >= dim[month]); ++month)
  337.     days -= (month==1) ? (28 + leap) : dim[month];
  338.  
  339.     da->min    = date->ds_Minute % 60;
  340.     da->hour   = date->ds_Minute / 60;
  341.     da->day    = days + 1;
  342.     da->month  = month + 1;
  343.     da->dow    = date->ds_Days % 7;    /*  0 = sunday    */
  344. }
  345.  
  346. void
  347. LoadCronFile()
  348. {
  349.     char buf[256];
  350.     long fh;
  351.     Command *cmd;
  352.  
  353.     while (cmd = (Command *)RemHead(&CmdList))
  354.     free(cmd);
  355.  
  356.     ReadLn(NULL, NULL, 0);
  357.     fh = (long)Open(CronFile, 1005);
  358.     if (fh == NULL) {
  359.     if (CronFileExists != -1)
  360.         logmessage("unable to open cronfile %s!\n", CronFile);
  361.     CronFileExists = -1;
  362.     return;
  363.     }
  364.     while (ReadLn(fh, buf, 256)) {
  365.     char *ptr = buf;
  366.     short i;
  367.  
  368.     if (buf[0] == 0 || buf[0] == '#')
  369.         continue;
  370.     cmd = (Command *)malloc(sizeof(Command));
  371.     setmem(cmd, sizeof(Command), 0);
  372.  
  373.     for (i = 0; i < 5; ++i) {               /*  5 time fields   */
  374.         /*
  375.         printf("lb %d\n", i);
  376.         */
  377.         LoadBitMap(&ptr, cmd->BitMap[i]);
  378.     }
  379.  
  380.     while (*ptr == ' ' || *ptr == 9)
  381.         ++ptr;
  382.     cmd->Command = malloc(strlen(ptr) + 1);
  383.     strcpy(cmd->Command, ptr);
  384.  
  385.     /*
  386.     for (i = 0; i < 5; ++i) {
  387.         for (j = 0; j < 4; ++j)
  388.         printf("%02x", cmd->BitMap[i][j]);
  389.         printf(" ");
  390.         for (j = 4; j < 8; ++j)
  391.         printf("%02x", cmd->BitMap[i][j]);
  392.         puts("");
  393.     }
  394.  
  395.     printf("cmd = %s\n", cmd->Command);
  396.     */
  397.  
  398.     AddTail(&CmdList, &cmd->Node);
  399.     }
  400.     Close(fh);
  401.     CronFileExists = 1;
  402. }
  403.  
  404. void
  405. LoadBitMap(pptr, bm)
  406. char **pptr;
  407. UBYTE *bm;    /*  8 bytes = 64 entries    */
  408. {
  409.     register char *ptr = *pptr;
  410.  
  411.     while (*ptr == ' ' || *ptr == 9)
  412.     ++ptr;
  413.  
  414.     /*
  415.      *    looking for *, number range n-n, single numbers, etc...  1,2,8-10 ...
  416.      */
  417.  
  418.     while (*ptr == '*' || (*ptr >= '0' && *ptr <= '9')) {
  419.     short v1, v2;
  420.  
  421.     v1 = 0;
  422.     while (*ptr >= '0' && *ptr <= '9') {
  423.         v1 = v1 * 10 + *ptr - '0';
  424.         ++ptr;
  425.     }
  426.     if (*ptr == '-') {
  427.         ++ptr;
  428.         v2 = 0;
  429.         while (*ptr >= '0' && *ptr <= '9') {
  430.         v2 = v2 * 10 + *ptr - '0';
  431.         ++ptr;
  432.         }
  433.     } else {
  434.         v2 = v1;
  435.     }
  436.     if (*ptr == '*') {
  437.         v1 = 0;
  438.         v2 = 63;
  439.         ++ptr;
  440.     }
  441.     if (v1 < 0)
  442.         v1 = 0;
  443.     if (v1 > 63)
  444.         v1 = 63;
  445.     if (v2 < 0)
  446.         v2 = 0;
  447.     if (v2 > 63)
  448.         v2 = 63;
  449.  
  450.     --v1;
  451.     do {
  452.         v1 = (v1 + 1) & 63;
  453.         bm[v1>>3] |= (1 << (v1 & 7));
  454.     } while (v1 != v2);
  455.     if (*ptr == ',')
  456.         ++ptr;
  457.     }
  458.     *pptr = ptr;
  459. }
  460.  
  461. /*
  462.  *  Poor man's log.  Note that the log file is not left open ... this allows
  463.  *  one to read or tail it at any time.
  464.  */
  465.  
  466. void
  467. logmessage(ptr, a, b, c, d, e)
  468. char *ptr;
  469. {
  470.     char *buf = malloc(512);
  471.     DATESTAMP date;
  472.     DateAry da;
  473.     long    fh;
  474.     static char *Dow[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
  475.     static char *Miy[] = { "---", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  476.                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
  477.  
  478.     if (!buf)
  479.     return;
  480.  
  481.     DateStamp(&date);
  482.     DateToDateAry(&date, &da);
  483.  
  484.     sprintf(buf, "dcron: %s %2ld %s %02ld:%02ld   ",
  485.     Dow[da.dow], da.day, Miy[da.month], da.hour, da.min
  486.     );
  487.     sprintf(buf+strlen(buf), ptr, a, b, c, d, e);
  488.     if ((fh = (long)Open(LogFile, 1005)) == NULL)
  489.     fh = (long)Open(LogFile, 1006);
  490.     if (fh) {
  491.     Seek(fh, 0L, 1);
  492.     WriteStr(fh, buf);
  493.     Close(fh);
  494.     }
  495.     free(buf);
  496. }
  497.  
  498. void
  499. WriteStr(fh, buf)
  500. long fh;
  501. char *buf;
  502. {
  503.     Write(fh, buf, strlen(buf));
  504. }
  505.  
  506. ReadLn(fh, buf, max)
  507. long fh;
  508. char *buf;
  509. short max;
  510. {
  511.     static char Data[1024];
  512.     static short RIdx, RLen;
  513.     register short i;
  514.  
  515.     if (fh == NULL) {
  516.     RIdx = RLen = 0;
  517.     return(0);
  518.     }
  519.     for (--max, i = 0; i < max; ++i) {
  520.     if (RIdx == RLen) {
  521.         RLen = Read(fh, Data, 1024);
  522.         RIdx = 0;
  523.         if (RLen <= 0) {
  524.         buf[i] = 0;
  525.         return(0);
  526.         }
  527.     }
  528.     if ((buf[i] = Data[RIdx++]) == '\n')
  529.         break;
  530.     }
  531.     buf[i] = 0;
  532.     return(1);
  533. }
  534.  
  535.