home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 492.lha / AmiCron_v4.2 / AmiCron.c < prev    next >
C/C++ Source or Header  |  1991-04-06  |  14KB  |  525 lines

  1. /****************************************************************************
  2.  *                                                                          *
  3.  *                              A M I C R O N                               *
  4.  *                                                                          *
  5.  *                         Version 4.2 - 03-Jan-91                          *
  6.  *                                                                          *
  7.  *                              by P. Sainio                                *
  8.  *                                                                          *
  9.  ****************************************************************************
  10.  
  11.     This is my version of AmiCron, I hope you like it... It's still
  12. in public domain so if you have any ideas let us know about them.
  13.  
  14.  *
  15.  *    amicron.c    (Version 2.5(a&L) by <CB>)
  16.  *
  17.  *    Public Domain (p) No Rights Reserved
  18.  *
  19.  *    This program operates as a daemon, waking up every minute
  20.  *    to execute the CRONTAB table.  
  21.  *
  22.  *    Put in startup-sequence like:
  23.  *        run newcli con:0/140/160/50/CronTask s:startcron
  24.  *    The startcron file needs to contains just one line:
  25.  *        amicron
  26.  *
  27.  *    Some notes are included below concerning the cron table
  28.  *    file format.  In this version the cron table file is left
  29.  *    on disk and not moved to core, and  the command character
  30.  *    to signify a newline '%' is not used.
  31.  *
  32.  *    Some cron table entry examples:
  33.  *
  34.  *    Print the date in the crontask window every minute:
  35.  *        * * * * * date
  36.  *
  37.  *    Print the date in the crontask window on the hour, every hour:
  38.  *        0 * * * * date
  39.  *
  40.  *    Run uupc at 4:30 am every day except Sat and Sun:
  41.  *        30 4 * * 1-5 uupc -siscuva
  42.  *
  43.  *    Backup the files every other day at 7:30 pm:
  44.  *        30 19 * * 1,3,5 sdbackup -s LAST dh0: incbkup_1:
  45.  *
  46.  */
  47.  
  48. /* 
  49.  * Public Domain (p) by S. R. Sampson
  50.  * Version 2.3, October 1987
  51.  * Amiga port by Rick Schaeffer October 1987
  52.  *
  53.  * Rick Schaeffer          UUCP:  seismo!uunet!iscuva!ricks!ricks
  54.  * E. 13611 26th Ave.      Phone: (509)928-3533
  55.  * Spokane, WA  99216
  56.  *
  57.  * Modified path for CronTab & CronErr to suit Amiga enviroment better
  58.  * Version 2.31  <CB> 15.12.87 
  59.  *
  60.  * Fixed bug with CronTab entries specifying an event by date (month)
  61.  * i.e. "* * 24 12 * say Merry christmas", now works!
  62.  * Version 2.32 <CB> 25.12.87
  63.  *
  64.  * Removed "CronErr", an obvious Unix "feature"
  65.  * Version 2.33 <CB> 31.12.87 
  66.  *
  67.  * Additional support for Lattice 4.0, changed to complete sleep (no more  
  68.  * 5 I/O ints. per second), added command line parameter for CronTab path.
  69.  * Added feature to align Cron to start on 01 seconds, including "loss"
  70.  * due to lengthy command calls or extensive I/O.
  71.  * Version 2.4 <CB> 10.01.88 
  72.  *
  73.  * GRRRRRRR. Just when I thought it was safe to release that thing, C=A brings
  74.  * out AmyDos 1.3. So to have the output of programs called by Cron visible, I
  75.  * changed the "Run >nil:" parameter for execute() back to "Run ". This means,                         
  76.  * that you will have to look at the annoying CLI[#] messages, each time some 
  77.  * program is called. I was pleased with the way the old RUN >nil: worked, and
  78.  * will try to convince Andy Finkel to bring it back.
  79.  * In the meantime, this is:
  80.  * Version 2.5 <CB> 27.03.88
  81.  *
  82.  * Changed it to use ARP.  There is two versions, one that detaches itself from
  83.  * self and the other that doesn't
  84.  * Version 4.2 <PS> 03.01.91
  85.  
  86.                         
  87. ______  /          
  88. ______\O                    - The Software Brewery - 
  89.       \\                          
  90.        o            Sparkling, fresh software from W.-Germany
  91.                  
  92.      @@@@@          Straight from the bar to your Amiga
  93.      |~~~|\        
  94.      | | |/        
  95.      |___|        With our regards to the Software Distillery
  96.  
  97. Members are (listed alphabetically):
  98. Christian Balzer alias <CB>, Lattice C, user interfaces, beer addict. 
  99. Christof Bonnkirch, Aztec C, telecommunications, money adict.
  100. Heiko Rath alias <HR>, Assembler, ROM-Kernal stuff, Marabou addict. 
  101. Peter Stark alias PS, Lattice C, IO & utilities, WordStar addict.
  102. Ralf Woitinas alias RAF, Assembler, anything, Ray-Tracing addict.
  103. Torsten Wronski alias MM, Assembler, anything, girls addict.
  104.  
  105. Beverages: Altenmuenster Brauer Bier, Urfraenkisches Landbier, Grohe Bock.
  106.  
  107. Send exotic drinks, comments, critizism, flames to:
  108.  
  109. The Software Brewery
  110. Christian Balzer
  111. Im Wingertsberg 45
  112. D-6108 Weiterstadt
  113. West-Germany
  114.  
  115. Our BBS "AmigaNode" isn't online yet. As soon as it becomes available, 
  116. you'll be the first to know :-).
  117.  
  118.  *
  119.  * Compilation notes:
  120.  * Program is compiled with Lattice C 5.05 and the makefile is included.
  121.  * I have removed some of the comments, sorry about that.  If you're
  122.  * intrested see the original source.
  123.  *
  124.  * NOTE!!!  There is no errorchecking for crontab-file...
  125.  */
  126.  
  127. #define MAXLINE    132
  128. #define SIZE    64
  129. #define ABSEXECBASE ((struct ExecBase **)4L)
  130. #define NOCRON "Can't get crontab-file"
  131. #define CRONPORT "AmiCronV4.2"
  132. #define NO_MESS_MEM "No memory for message!"
  133. #define NO_REPLY "Could not create replyport!"
  134. #define ERR_IN_FILE "Error reading crontab-file!"
  135. #define NO_DEVICE "Could not open timer.device!"
  136. #define NO_TIMER_PORT "Could not open timerport!"
  137. #define NO_CRON_PORT "Could not create CronPort!"
  138. #define EXITING "Quiting the AmiCron!"
  139.  
  140. struct cronmsg {
  141.     struct Message cm_Msg;
  142.     char *newfile;
  143. };
  144.  
  145. struct iobuf {
  146.     unsigned char *base;
  147.     unsigned char *ptr;
  148.     int rcnt;
  149.     int size;
  150. };
  151.  
  152. typedef char boolean;
  153.  
  154. extern struct ArpBase *ArpBase;
  155. extern struct DOSBase *DOSBase;
  156. extern struct IntuitionBase *IntuitionBase;
  157.  
  158. struct MsgPort *timerport,*cronport,*mycron=NULL,*replyport;
  159. struct iobuf fd;
  160. struct cronmsg *newcron;
  161.  
  162. struct NewShell nsh;
  163. struct timerequest tr;
  164.  
  165. char min[SIZE],hour[SIZE],day[SIZE],month[SIZE],wday[SIZE],command[SIZE],eof,
  166.         *tokv[]={min,hour,day,month,wday},
  167.         *com="CronFile",*args,*help="Usage: AmiCron [CronFile]",
  168.         cronfile[256]="S:CronTab";
  169.  
  170. struct TextAttr myfont = {
  171.     "topaz.font",
  172.     TOPAZ_EIGHTY,0,0 };
  173.  
  174. struct IntuiText body1={
  175.     0,1,JAM1,10,5,&myfont,NULL,NULL },body2={
  176.     0,1,JAM1,10,14,&myfont,NULL,NULL },no1={
  177.     0,1,JAM1,6,3,&myfont,"Cancel",NULL },no2={
  178.     0,1,JAM1,6,3,&myfont,"Quit",NULL };
  179.  
  180. static void cleanup(void),alarm(int),wakeup(void),MyExit(void);
  181. static ULONG systime(void);
  182. static boolean getline(void),getfile(void),
  183.                     match(register char *,register int);
  184. static char *scanner(register char *,register char *),
  185.                 *fgets(char *,int);
  186.  
  187. void __asm __saveds AmiCron(register __a0 char *cmd,register __d0 long len) {
  188.  
  189.     ULONG current,signals,getsigs,timesig,messig;
  190.     long count;
  191.     register struct tm *tm;
  192.  
  193.     count=GADS(cmd,len,help,&args,com);
  194.     if (count<0) {
  195.         body1.IText=args;
  196.         AutoRequest(NULL,&body1,NULL,&no1,0,0,188,50);
  197.         cleanup();
  198.     }
  199.  
  200.     if (count)
  201.         strcpy(cronfile,args);
  202.  
  203.     Forbid();
  204.  
  205.     if (mycron=FindPort(CRONPORT)) {
  206.         Permit();
  207.         if (replyport=CreatePort(0,0)) {
  208.             if (newcron=AllocMem(sizeof(struct cronmsg),
  209.                                         MEMF_PUBLIC|MEMF_CLEAR)) {
  210.                 newcron->cm_Msg.mn_Node.ln_Type=NT_MESSAGE;
  211.                 newcron->cm_Msg.mn_ReplyPort=replyport;
  212.                 newcron->newfile=cronfile;
  213.                 PutMsg(mycron,newcron);
  214.                 WaitPort(replyport);
  215.                 FreeMem(newcron,sizeof(struct cronmsg));
  216.             }
  217.             else {
  218.                 body1.IText=NO_MESS_MEM;
  219.                 AutoRequest(NULL,&body1,NULL,&no1,0,0,sizeof(NO_MESS_MEM)*8+44,50);
  220.             }
  221.             DeletePort(replyport);
  222.         }
  223.         else {
  224.             body1.IText=NO_REPLY;
  225.             AutoRequest(NULL,&body1,NULL,&no1,0,0,sizeof(NO_REPLY)*8+44,50);
  226.         }
  227.         cleanup();
  228.     }
  229.  
  230.     else {
  231.         if (!(cronport=CreatePort(CRONPORT,0))) {
  232.             body1.IText=NO_CRON_PORT;
  233.             AutoRequest(NULL,&body1,NULL,&no1,0,0,sizeof(NO_CRON_PORT)*8+44,50);
  234.             cleanup();
  235.         }
  236.     }
  237.     Permit();
  238.  
  239.     if (timerport=CreatePort(0,0)) {
  240.         tr.tr_node.io_Message.mn_Node.ln_Type=NT_MESSAGE;
  241.         tr.tr_node.io_Message.mn_Length=sizeof(struct timerequest);
  242.         tr.tr_node.io_Message.mn_ReplyPort=timerport;
  243.  
  244.         if (!OpenDevice(TIMERNAME,UNIT_VBLANK,&tr,0)) {
  245.             if (getfile()) {
  246.                 signals=SIGBREAKF_CTRL_C|(timesig = 1<<timerport->mp_SigBit)|
  247.                             (messig = 1<<cronport->mp_SigBit);
  248.                 for (;;) {
  249.                     wakeup();
  250.                     current=systime();
  251.                     tm=localtime(¤t);
  252.                     alarm(60-tm->tm_sec);
  253.                     do {
  254.                         getsigs=Wait(signals);
  255.                         if (getsigs & SIGBREAKF_CTRL_C)
  256.                             cleanup();
  257.                         if (getsigs & messig) {
  258.                             if (newcron=(struct cronmsg *)GetMsg(cronport)) {
  259.                                 strcpy(cronfile,newcron->newfile);
  260.                                 ReplyMsg(newcron);
  261.                                 DosFreeMem(fd.base);
  262.                                 fd.base=NULL;
  263.                                 if (!getfile())
  264.                                     cleanup();
  265.                             }
  266.                         }
  267.                     }
  268.                     while (!(getsigs & timesig));
  269.                 }
  270.             }
  271.         }
  272.     }
  273.     cleanup();
  274. }
  275.  
  276. static void wakeup() {
  277.  
  278.     register struct tm *tm;
  279.     long cur_time;
  280.      
  281.     cur_time=systime();        /* get the current time */
  282.     tm = localtime(&cur_time);    /* break it down */
  283.  
  284.     /* Now let's see if there is a CronTab file out there <CB> */     
  285.  
  286.     eof = FALSE;
  287.  
  288.     while (!eof)  {
  289.         if (getline() && match(min,tm->tm_min) &&
  290.            match(hour,tm->tm_hour) && match(day,tm->tm_mday) &&
  291.            match(month,tm->tm_mon+1) && match(wday,tm->tm_wday))  {
  292.         /* Weird localtime months ^ range from 0-11 !!! <CB>*/
  293.             nsh.nsh_Pri=(*ABSEXECBASE)->ThisTask->tc_Node.ln_Pri;
  294.             nsh.nsh_Control=BACKGROUND_SHELL;
  295.             nsh.nsh_Input=Input();
  296.             nsh.nsh_Output=Output();
  297.             ASyncRun(command,NULL,(struct ProcessControlBlock *)&nsh);
  298.         }
  299.     }
  300. }
  301.  
  302.  
  303. /*
  304.  *    A line consists of six fields.  The first five are:
  305.  *
  306.  *        minute:         0-59
  307.  *        hour:           0-23
  308.  *        day:            1-31
  309.  *        month:          1-12
  310.  *        weekday:        0-6 (Sunday = 0)
  311.  *
  312.  *    The fields are seperated by spaces or tabs, with the
  313.  *    first field left justified (no leading spaces or tabs).
  314.  *    See below for optional field syntax.
  315.  *
  316.  *    The last field is the command field.  This command will
  317.  *    be executed by the CLI just as if typed from a console.
  318.  */
  319.  
  320. static boolean getline() {
  321.     register char *p;
  322.     register int   i;
  323.     char buffer[MAXLINE];
  324.  
  325.     if (fgets(buffer,sizeof buffer) == NULL)  {
  326.         eof = TRUE;
  327.         return(FALSE);
  328.     }
  329.  
  330.     for (p = buffer, i = 0; i < 5; i++)  {
  331.         if ((p = scanner(tokv[i], p)) == (char *)NULL)
  332.             return(FALSE);
  333.     }
  334.  
  335.     strcpy(command, p);     /* scoop the command */
  336.     return(TRUE);
  337. }
  338.  
  339.  
  340. static char *scanner(register char *token,register char *offset) {
  341.     /*    *token    target buffer to receive scanned token */
  342.     /*    *offset    place holder into source buffer */
  343.     while ((*offset != ' ') && (*offset != '\t') && *offset)
  344.         *token++ = *offset++;
  345.  
  346.     /*
  347.      *      Check for possible error condition
  348.      */
  349.          
  350.     if (!*offset)
  351.         return ((char *)NULL);
  352.  
  353.     *token = '\0';
  354.         
  355.     while ((*offset == ' ') || (*offset == '\t'))
  356.         offset++;
  357.  
  358.     return (offset);
  359. }
  360.  
  361.  
  362. /*
  363.  *    This routine will match the left string with the right number.
  364.  *
  365.  *    The string can contain the following syntax:
  366.  *
  367.  *    *        This will return TRUE for any number
  368.  *    x,y [,z, ...]    This will return TRUE for any number given.
  369.  *    x-y        This will return TRUE for any number within
  370.  *            the range of x thru y.
  371.  */
  372.  
  373. static boolean match(register char *left,register int right) {
  374.  
  375.     register int    n;
  376.     register char    c;
  377.  
  378.     n = 0;
  379.  
  380.     if (!strcmp(left, "*"))
  381.         return(TRUE);
  382.  
  383.     while ((c = *left++) && (c >= '0') && (c <= '9'))
  384.         n  =  (n * 10) + c - '0';
  385.  
  386.     switch (c)  {
  387.         case '\0':
  388.             return ((boolean)(right == n));
  389.  
  390.         case ',':
  391.             if ((boolean)(right == n))
  392.                 return(TRUE);
  393.             do {
  394.                 n = 0;
  395.                 while ((c = *left++) && (c >= '0') && (c <= '9'))
  396.                     n = (n * 10) + c - '0';
  397.                  if (right == n)
  398.                     return(TRUE);
  399.             } while (c == ',');
  400.             return(FALSE);
  401.  
  402.         case '-':
  403.             if (right < n)
  404.                 return(FALSE);
  405.  
  406.             n = 0;
  407.             while ((c = *left++) && (c >= '0') && (c <= '9'))
  408.                 n = (n * 10) + c - '0';
  409.  
  410.             return((boolean)(right <= n));
  411.     }
  412. }
  413.  
  414. static boolean getfile(void) {
  415.  
  416.     BPTR lock,file;
  417.     struct FileInfoBlock *fib;
  418.     boolean succ=FALSE;
  419.  
  420.     if (lock=Lock(cronfile,ACCESS_READ)) {
  421.         if (fib=AllocMem(sizeof(struct FileInfoBlock),MEMF_PUBLIC)) {
  422.             if (Examine(lock,fib)) {
  423.                 if (fd.base=DosAllocMem(fib->fib_Size)) {
  424.                     if (file=Open(cronfile,MODE_OLDFILE)) {
  425.                         fd.size=Read(file,fd.base,fib->fib_Size);
  426.                         if (fd.size=fib->fib_Size)
  427.                             fd.ptr=fd.base;
  428.                             succ=TRUE;
  429.                         Close(file);
  430.                     }
  431.                 }
  432.             }
  433.             FreeMem(fib,sizeof(struct FileInfoBlock));
  434.         }
  435.         UnLock(lock);
  436.     }
  437.     if (!succ) {
  438.  
  439.         long length;
  440.  
  441.         body1.IText=NOCRON;
  442.         body1.NextText=&body2;
  443.         body2.IText=cronfile;
  444.         length=strlen(cronfile);
  445.  
  446.         AutoRequest(NULL,&body1,NULL,&no1,0,0,((length>sizeof(NOCRON))?
  447.                         length : sizeof(NOCRON))*8+44,59);
  448.     }
  449.     return succ;
  450. }
  451.  
  452. static char *fgets(char *buffer,int len) {
  453.  
  454.     unsigned char ch;
  455.     int count=0;
  456.  
  457.     while (len>count) {
  458.         if (fd.rcnt<fd.size) {
  459.             if ((ch=*fd.ptr++)=='\n') {
  460.                 buffer[count++]='\0';
  461.                 fd.rcnt++;
  462.                 return buffer;
  463.             }
  464.             buffer[count++]=ch;
  465.             fd.rcnt++;
  466.         }
  467.         else {
  468.             fd.rcnt=0;
  469.             fd.ptr=fd.base;
  470.             if (count==0)
  471.                 return NULL;
  472.             else {
  473.                 buffer[count]='\0';
  474.                 return buffer;
  475.             }
  476.         }
  477.     }
  478. }
  479.  
  480. static ULONG systime() {
  481.     tr.tr_node.io_Command=TR_GETSYSTIME;
  482.     DoIO(&tr);
  483.     return (tr.tr_time.tv_secs+(((8*365+2)*24+6)*60*60));
  484.     /* To Greenwich Mean Time  ^^^^^^^^^^^^^^^^^^^^^ */
  485. }
  486.  
  487. static void alarm(int secs) {
  488.     tr.tr_node.io_Command=TR_ADDREQUEST;
  489.     tr.tr_time.tv_secs=secs;
  490.     tr.tr_time.tv_micro=0;
  491.     SendIO(&tr);
  492. }
  493.  
  494. static void cleanup() {
  495.     if (cronport) {
  496.         Forbid();
  497.         while (newcron=(struct cronmsg *)GetMsg(cronport))
  498.             ReplyMsg(newcron);
  499.         DeletePort(cronport);
  500.         Permit();
  501.         if (fd.base)
  502.             DosFreeMem(fd.base);
  503.         if (timerport) {
  504.             if (tr.tr_node.io_Device) {
  505.                 if (tr.tr_node.io_Command)
  506.                     AbortIO(&tr);
  507.                 CloseDevice(&tr);
  508.             }
  509.             else {
  510.                 body1.IText=NO_DEVICE;
  511.                 AutoRequest(NULL,&body1,NULL,&no1,0,0,sizeof(NO_DEVICE)*8+44,50);
  512.             }
  513.             DeletePort(timerport);
  514.         }
  515.         else {
  516.             body1.IText=NO_TIMER_PORT;
  517.             AutoRequest(NULL,&body1,NULL,&no1,0,0,sizeof(NO_TIMER_PORT)*8+44,50);
  518.         }
  519.         body1.IText=EXITING;
  520.         body1.NextText=NULL;
  521.         AutoRequest(NULL,&body1,NULL,&no2,0,0,sizeof(EXITING)*8+44,50);
  522.     }
  523.     MyExit();
  524. }
  525.