]> granicus.if.org Git - fcron/commitdiff
added option strict and noticenotrun
authorthib <thib>
Sat, 27 Jan 2001 15:41:09 +0000 (15:41 +0000)
committerthib <thib>
Sat, 27 Jan 2001 15:41:09 +0000 (15:41 +0000)
conf.c
database.c
option.h

diff --git a/conf.c b/conf.c
index ada26a15de472ff3d5f7843ad366ea6e0c7ea911..4044921fd30c24acb567b069954048a660a49b50 100644 (file)
--- a/conf.c
+++ b/conf.c
@@ -22,7 +22,7 @@
  *  `LICENSE' that comes with the fcron source distribution.
  */
 
- /* $Id: conf.c,v 1.36 2001-01-12 21:43:41 thib Exp $ */
+ /* $Id: conf.c,v 1.37 2001-01-27 15:41:09 thib Exp $ */
 
 #include "fcron.h"
 
@@ -495,11 +495,43 @@ read_file(const char *file_name, CF *cf)
            cl->cl_runas = runas;
        }
 
+       /* we need that here because the user's name (contained in the
+        * struct CF may be required */
+       cl->cl_file = cf;
+
+       /* check if the task has not been stopped during execution and
+        * insert in lavg or serial queues the jobs which was in one
+        * at fcron's stop and the bootrun jobs */
+       if (cl->cl_numexe > 0) {
+           cl->cl_numexe = 0;
+           if ( ! is_strict(cl->cl_option) ) {
+               if ( is_lavg(cl->cl_option) )
+                   add_lavg_job(cl);
+               else if ( is_serial(cl->cl_option) 
+                         || is_serial_once(cl->cl_option) )
+                   add_serial_job(cl);
+               else {
+                   /* job has been stopped during execution :
+                    * launch it again */
+                   warn("job %s did not finish : running it again.",
+                        cl->cl_shell);
+                   set_serial_once(cl->cl_option);
+                   add_serial_job(cl);
+               }
+           }
+       }
+
        if ( is_td(cl->cl_option) ) {
     
            /* set the time and date of the next execution  */
            if ( cl->cl_nextexe <= now ) {
-               if ( is_bootrun(cl->cl_option) && t_save != 0) {
+               if ( cl->cl_nextexe == 0 )
+                   /* the is a line from a new file */
+                   set_next_exe(cl, NO_GOTO);              
+               else if(cl->cl_runfreq == 1 && is_notice_notrun(cl->cl_option))
+                   set_next_exe_notrun(cl, SYSDOWN);
+               else if ( is_bootrun(cl->cl_option) && t_save != 0 
+                         && cl->cl_runfreq != 1) {
                    if ( cl->cl_remain > 0 && --cl->cl_remain > 0 ) {
                        debug("    cl_remain: %d", cl->cl_remain);
                    }
@@ -510,10 +542,13 @@ read_file(const char *file_name, CF *cf)
                        if ( ! is_lavg(cl->cl_option) )
                            set_serial_once(cl->cl_option);
                    }
-                   set_next_exe(cl, 0);
+                   set_next_exe(cl, STD);
+               }
+               else {
+                   if ( is_notice_notrun(cl->cl_option) )
+                       mail_notrun(cl, SYSDOWN, NULL);
+                   set_next_exe(cl, NO_GOTO);
                }
-               else
-                   set_next_exe(cl, 1);
            }
            else
                insert_nextexe(cl);
@@ -526,25 +561,6 @@ read_file(const char *file_name, CF *cf)
            insert_nextexe(cl);
        }           
 
-       /* check if the task has not been stopped during execution and
-        * insert in lavg or serial queues the jobs which was in one
-        * at fcron's stop and the bootrun jobs */
-       if (cl->cl_numexe > 0) {
-           cl->cl_numexe = 0;
-           if ( is_lavg(cl->cl_option) )
-               add_lavg_job(cl);
-           else if (is_serial(cl->cl_option) || is_serial_once(cl->cl_option))
-               add_serial_job(cl);
-           else {
-               /* job has been stopped during execution :
-                * launch it again */
-               warn("job %s did not finish : running it again.",
-                    cl->cl_shell);
-               set_serial_once(cl->cl_option);
-               add_serial_job(cl);
-           }
-       }
-
        if (debug_opt) {
            struct tm *ftime;
            ftime = localtime( &(cl->cl_nextexe) );
@@ -557,7 +573,6 @@ read_file(const char *file_name, CF *cf)
 
        cl->cl_next = cf->cf_line_base;
        cf->cf_line_base = cl;
-       cl->cl_file = cf;
        Alloc(cl, CL);
     }
     /* check for an error */
@@ -568,11 +583,6 @@ read_file(const char *file_name, CF *cf)
     /* free last calloc : unused */
     free(cl);
     
-/* // if (fgets(buf, sizeof(buf), ff) == NULL || */
-/* //  strncmp(buf, "eof\n", sizeof("eof\n")) != 0) */
-/* //  error("file %s is truncated : you should reinstall it with fcrontab",
-   file_name); */
-
     fclose(ff);
 
     return 0;
index 0c24129354794851eb674b8aa57cdf0baa8acf74..6786ad461ab0d0103a285ef593ded2c013aa91ba 100644 (file)
  *  `LICENSE' that comes with the fcron source distribution.
  */
 
- /* $Id: database.c,v 1.43 2001-01-12 21:44:45 thib Exp $ */
+ /* $Id: database.c,v 1.44 2001-01-27 15:44:39 thib Exp $ */
 
 #include "fcron.h"
 
 int is_leap_year(int year);
 int get_nb_mdays(int year, int mon);
 void set_wday(struct tm *date);
-void goto_non_matching(CL *line, struct tm *tm);
+void goto_non_matching(CL *line, struct tm *tm, char option);
 void run_normal_job(CL *line);
 void run_serial_job(void);
 void run_lavg_job(int i);
@@ -37,7 +37,7 @@ void run_queue_job(CL *line);
 
 
 void
-test_jobs(time_t t2)
+test_jobs(void)
   /* determine which jobs need to be run, and run them. */
 {
     struct job *j;
@@ -46,9 +46,9 @@ test_jobs(time_t t2)
     debug("Looking for jobs to execute ...");
 /*      // */
 
-    while ( (j=queue_base) && j->j_line->cl_nextexe <= t2 ){
-       set_next_exe(j->j_line, 0);
+    while ( (j=queue_base) && j->j_line->cl_nextexe <= now ){
        if ( j->j_line->cl_remain > 0 && --(j->j_line->cl_remain) > 0) {
+           set_next_exe(j->j_line, STD);
            debug("    cl_remain: %d", j->j_line->cl_remain);
            continue ;
        }
@@ -61,6 +61,8 @@ test_jobs(time_t t2)
            add_serial_job(j->j_line);
        else
            run_normal_job(j->j_line);
+       
+       set_next_exe(j->j_line, STD);
     }
 
 }
@@ -280,6 +282,8 @@ add_serial_job(CL *line)
 void
 add_lavg_job(CL *line)
     /* add the next queued job in lavg queue */
+    /* WARNING : must be run before a set_next_exe() to get the strict option
+     * working correctly */
 {
 
     /* check if the line is already in the lavg queue */
@@ -322,9 +326,35 @@ add_lavg_job(CL *line)
 
     lavg_array[lavg_num].l_line = line;
     line->cl_numexe += 1;
-    lavg_array[lavg_num++].l_until = 
-       (line->cl_until > 0) ? now + line->cl_until : 0;
+    set_run_if_late(line->cl_option);
+    if ( is_strict(line->cl_option) && line->cl_runfreq == 1) {
+       struct tm *ft;
+       struct tm ftime;
+       time_t end_of_cur_int = 0;
+
+       ft = localtime(&line->cl_nextexe);
+
+       /* localtime() function seem to return every time the same pointer :
+          it resets our previous changes, so we need to prevent it
+          ( localtime() is used in the debug() function) */
+       memcpy(&ftime, ft, sizeof(struct tm));
+
+       goto_non_matching(line, &ftime, END_OF_INTERVAL);
+
+       end_of_cur_int = mktime(&ftime);
+
+       if ((line->cl_until > 0) && (line->cl_until + now < end_of_cur_int))
+           lavg_array[lavg_num].l_until = line->cl_until + now;
+       else {
+           lavg_array[lavg_num].l_until = end_of_cur_int;
+           clear_run_if_late(line->cl_option);
+       }
+    }
+    else
+       lavg_array[lavg_num].l_until = 
+           (line->cl_until > 0) ? now + line->cl_until : 0;
 
+    lavg_num++;
 }
 
 
@@ -502,11 +532,11 @@ set_wday(struct tm *date)
 
 
 void
-goto_non_matching(CL *line, struct tm *ftime)
+goto_non_matching(CL *line, struct tm *ftime, char option)
     /* search the first the nearest time and date that does
      * not match the line */
 {
-    if ( is_freq_periodically(line->cl_option)) {
+    if ( is_freq_periodically(line->cl_option) && option != END_OF_INTERVAL) {
        int max = get_nb_mdays(ftime->tm_year, ftime->tm_mon);
        if (is_freq_mid(line->cl_option)) {
            if (is_freq_mins(line->cl_option))
@@ -593,7 +623,7 @@ goto_non_matching(CL *line, struct tm *ftime)
        }
        if (debug_opt)
            set_wday(ftime);
-       debug("   %s first non matching %d/%d/%d wday:%d %02d:%02d",
+       debug("   %s beginning of next period %d/%d/%d wday:%d %02d:%02d",
              line->cl_shell, (ftime->tm_mon + 1), ftime->tm_mday,
              (ftime->tm_year + 1900), ftime->tm_wday,
              ftime->tm_hour, ftime->tm_min);
@@ -612,6 +642,10 @@ goto_non_matching(CL *line, struct tm *ftime)
        char ignore_mons = (is_freq_mons(line->cl_option)) ? 1:0;
        char ignore_dow = (is_freq_dow(line->cl_option)) ? 1:0;
     
+       if (option == END_OF_INTERVAL)
+           /* we want to go to the end of the current interval */
+           ignore_mins=ignore_hrs=ignore_days=ignore_mons=ignore_dow = 0;
+
        /* */
        debug("   ignore: %d %d %d %d %d", ignore_mins, ignore_hrs,
              ignore_days, ignore_mons, ignore_dow);
@@ -671,9 +705,15 @@ goto_non_matching(CL *line, struct tm *ftime)
                }
            }
        }
-         
-       debug("   %s first non matching %d/%d/%d wday:%d %02d:%02d",
-             line->cl_shell, (ftime->tm_mon + 1), ftime->tm_mday,
+
+       if (option == END_OF_INTERVAL)
+           /* we want the end of the current interval, not the beginning
+            * of the first non-matching interval */
+           ftime->tm_min--;
+       
+       debug("   %s %s %d/%d/%d wday:%d %02d:%02d", line->cl_shell,
+             (option == STD) ? "first non matching" : "end of interval",
+             (ftime->tm_mon + 1), ftime->tm_mday,
              (ftime->tm_year + 1900), ftime->tm_wday,
              ftime->tm_hour, ftime->tm_min);
        return;
@@ -682,7 +722,7 @@ goto_non_matching(CL *line, struct tm *ftime)
 
 
 void 
-set_next_exe(CL *line, char is_new_line)
+set_next_exe(CL *line, char option)
   /* set the cl_nextexe of a given CL and insert it in the queue */
 {
 
@@ -708,8 +748,8 @@ set_next_exe(CL *line, char is_new_line)
        /* to prevent multiple execution in the same minute */
        ftime.tm_min += 1;
        ftime.tm_sec = 0;
-       if ( line->cl_runfreq == 1 && ! is_new_line )
-           goto_non_matching(line, &ftime);
+       if (line->cl_runfreq==1 && option != NO_GOTO && option != NO_GOTO_LOG)
+           goto_non_matching(line, &ftime, STD);
 
       setMonth:
        for (i = ftime.tm_mon; (bit_test(line->cl_mons, i)==0) && (i<12); i++);
@@ -842,7 +882,7 @@ set_next_exe(CL *line, char is_new_line)
       set_cl_nextexe:    
        line->cl_nextexe = mktime(&ftime);
 
-       if ( ! is_new_line )
+       if ( option != NO_GOTO )
            debug("   cmd: %s next exec %d/%d/%d wday:%d %02d:%02d",
                  line->cl_shell, (ftime.tm_mon + 1), ftime.tm_mday,
                  (ftime.tm_year + 1900), ftime.tm_wday,
@@ -856,20 +896,129 @@ set_next_exe(CL *line, char is_new_line)
              line->cl_timefreq);
     }
     
-
     insert_nextexe(line);
 
-       
+}
+
+
+void
+set_next_exe_notrun(CL *line, char context)
+    /* set the time of the next execution and send a mail to tell him the job
+     * has not run if necessary */
+{
+    time_t next_period = 0;
+    struct tm *ft = NULL;
+    struct tm ftime, last_nextexe;
+    char set_next_exe_opt = 0;
+
+/*  // */
+    debug("  set_next_exe_notrun : %s %d", line->cl_shell, context);
+/*  // */
+
+    if (context == SYSDOWN) {
+       ft = localtime(&line->cl_nextexe);
+       set_next_exe_opt = NO_GOTO;
+    }
+    else {
+       ft = localtime(&now);
+       set_next_exe_opt = NO_GOTO_LOG;
+    }
+    
+    /* localtime() function seem to return every time the same pointer :
+       it resets our previous changes, so we need to prevent it
+       ( localtime() is used in the debug() function) */
+    memcpy(&ftime, ft, sizeof(struct tm));
+    /* we also copy it to last_nextexe which will be used in mail_notrun */
+    memcpy(&last_nextexe, ft, sizeof(struct tm));
+    
+    ftime.tm_sec = 0;
+    goto_non_matching(line, &ftime, STD);
+    next_period = mktime(&ftime);
+
+    set_next_exe(line, set_next_exe_opt);
+    if ( line->cl_nextexe >= next_period ) {
+       /* line has not run during one or more period(s) : send a mail */
+       mail_notrun(line, context, &last_nextexe);
+    }
 
 }
 
+void
+mail_notrun(CL *line, char context, struct tm *last_nextexe)
+    /* send a mail to tell user a %-job has not run (and why) */
+{
+    int pid = 0;
+    int fd = 0;
+
+    switch ( pid = fork() ) {
+    case -1:
+       error_e("Fork error : could not mail for not run %s", line->cl_shell);
+       return;
+    case 0:
+       /* child */
+       break;
+    default:
+       /* parent */
+
+/*  // */
+       debug("Reporting by mail non execution of %s (pid %d)", 
+             line->cl_shell, pid);
+/*  // */
+
+       /* create a entry in exe_array */
+       if ( exe_num >= exe_array_size ) {
+           struct exe *ptr = NULL;
+           short int old_size = exe_array_size;
+           
+           debug("Resizing exe_array");
+           exe_array_size = (exe_array_size + EXE_GROW_SIZE);
+           
+           if ( (ptr = calloc(exe_array_size, sizeof(struct exe))) == NULL )
+               die_e("could not calloc exe_array");
+           
+           memcpy(ptr, exe_array, (sizeof(struct exe) * old_size));
+           free(exe_array);
+           exe_array = ptr;
+       }
+       /* set line to NULL as this is not a line ... */
+       exe_array[exe_num].e_line = NULL;
+       exe_array[exe_num].e_pid = pid;
+       exe_num++;
+       return;
+    }
+
+    if ( last_nextexe == NULL )
+       last_nextexe = localtime(&line->cl_nextexe);
+
+    /* create a temp file, and write in it the message to send */
+    fd = create_mail(line, "Non-execution of fcron job");
+
+    if (context == SYSDOWN) {
+       xwrite(fd, "Line has not run since x due to system's down state.\n");
+    }
+    else if (context == LAVG) {
+       xwrite(fd, "Line has not run since x due to a too high system load"
+              " average or too many lavg-serial job.\n");
+    }
+    
+    /* become user (for security reasons) */
+    if (change_user(line->cl_runas) < 0)
+       return ;
+
+    /* then, send mail */
+    launch_mailer(line, fd);
+    
+    /* we should not come here : launch_mailer does not return */
+    error("mail_notrun : launch_mailer failed");
+    
+}
 
 time_t
 check_lavg(time_t lim)
     /* run a job based on system load average if one should be run
      * and return the time to sleep */
 {
-    time_t tts = time_to_sleep(lim);
+    time_t tts = 0;
 
 #ifdef NOLOADAVG
     while ( lavg_num > 0 )
@@ -886,13 +1035,40 @@ check_lavg(time_t lim)
 
     /* first, check if some lines must be executed because of until */
     while ( i < lavg_num )
-       if ( lavg_array[i].l_line->cl_until && lavg_array[i].l_until < now ) {
-           debug("until %s %d", lavg_array[i].l_line->cl_shell,
-                 lavg_array[i].l_until);
-           run_lavg_job(i);
+       if ( (lavg_array[i].l_line->cl_until > 0 
+             || lavg_array[i].l_line->cl_runfreq == 1)
+            && lavg_array[i].l_until < now){
+           if ( ! is_run_if_late(lavg_array[i].l_line->cl_option) ) {
+               explain("Interval of execution exceeded : %s (not run)",
+                       lavg_array[i].l_line->cl_shell);
+
+               /* set time of the next execution and send a mail if needed */
+               if ( is_notice_notrun(lavg_array[i].l_line->cl_option) )
+                   set_next_exe_notrun(lavg_array[i].l_line, LAVG);
+               else
+                   set_next_exe(lavg_array[i].l_line, NO_GOTO_LOG);
+
+               /* remove this job from the lavg queue */
+               lavg_array[i].l_line->cl_numexe -= 1;
+               if (i < --lavg_num) {
+                   lavg_array[i] = lavg_array[lavg_num];
+                   lavg_array[lavg_num].l_line = NULL;
+               }
+               else
+                   lavg_array[i].l_line = NULL;
+
+           }
+           else {
+               debug("until %s %d", lavg_array[i].l_line->cl_shell,
+                     lavg_array[i].l_until);
+               run_lavg_job(i);
+           }
        } else
            i++;
 
+    /* we do this set here as the nextexe of lavg line may change before */
+    tts = time_to_sleep(lim);
+
     if ( lavg_num == 0 )
        return tts;
        
index 2d15275ec76d2693f687264ae5929795882edb7f..c53faa7ef9f95a7e7f955a0276ed638f7d215796 100644 (file)
--- a/option.h
+++ b/option.h
@@ -21,7 +21,7 @@
  *  `LICENSE' that comes with the fcron source distribution.
  */
 
- /* $Id: option.h,v 1.14 2001-01-15 18:46:39 thib Exp $ */
+ /* $Id: option.h,v 1.15 2001-01-27 15:45:08 thib Exp $ */
 
 /* This has been inspired from bitstring(3) : here is the original copyright :
  */
@@ -64,7 +64,7 @@
   6      is this job should be run serially only once (for bootrun) ?
   7      does the output have to be mailed to user ?
   8      does the output (even if zero-length) must be mailed to user ?
-  9  ****** bit 9 unused **********************
+  9      if time of execution is exceeded, exec the lavg job or not ?
   10     can this job be executed several times simultaneously
   11     can this job be put several times in the serial queue simultaneously
   12     can this job be put several times in the lavg queue simultaneously
 
 
 /*
-  bit 9 : currently unused
+  bit 9 : set to 1 : exec the job now if time of execution is exceeded
+          set to 0 : do not exec the job if time of execution is exceeded
 */
+#define        is_run_if_late(opt) \
+       (_bit_test(opt, 9))
+#define        set_run_if_late(opt) \
+       (_bit_set(opt, 9))
+#define clear_run_if_late(opt) \
+       (_bit_clear(opt, 9))
 
 
 /*
            set to 0 : let the job in the %-queue if interval is exceeded
 */
 #define        is_strict(opt) \
-       (_bit_test(opt, 20))
+       ( ! _bit_test(opt, 20))
 #define        set_strict(opt) \
-       (_bit_set(opt, 20))
-#define clear_strict(opt) \
        (_bit_clear(opt, 20))
+#define clear_strict(opt) \
+       (_bit_set(opt, 20))
 
 
 /*