]> granicus.if.org Git - fcron/commitdiff
support of queues
authorthib <thib>
Wed, 31 May 2000 19:11:15 +0000 (19:11 +0000)
committerthib <thib>
Wed, 31 May 2000 19:11:15 +0000 (19:11 +0000)
conf.c
database.c
fcron.c
fcron.h
global.h
job.c

diff --git a/conf.c b/conf.c
index 5f945276b42c78429c3662b2df1e9dd6cf14c4f7..37877ee785a43091cc5a7583ce51e9c060a60698 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.3 2000-05-30 19:25:41 thib Exp $ */
+ /* $Id: conf.c,v 1.4 2000-05-31 19:11:15 thib Exp $ */
 
 #include "fcron.h"
 
@@ -253,8 +253,10 @@ synchronize_file(char *file_name)
                         memcmp(new_l->cl_mins, old_l->cl_mins, size) == 0
                        ) {
                        
-                       new_l->cl_remain = old_l->cl_remain; 
-                       new_l->cl_nextexe = old_l->cl_nextexe; 
+                       new_l->cl_remain = old_l->cl_remain;
+                       if ( (new_l->cl_nextexe = old_l->cl_nextexe) > 0 )
+                           insert_nextexe(new_l);
+                       else insert_freq(new_l);
 
                        if (debug_opt) {
                            if (new_l->cl_nextexe > 0) {
@@ -443,7 +445,7 @@ read_file(const char *file_name, CF *cf)
            if ( cl->cl_nextexe <= ti )
                set_next_exe(cl, 1);
        } else {
-
+           insert_freq(cl);
            debug("   remain: %ld  timefreq: %ld", cl->cl_remain,
                  cl->cl_timefreq);
        }           
@@ -464,12 +466,14 @@ read_file(const char *file_name, CF *cf)
                /* we don't set cl_nextexe to 0 because this value is 
                 * reserved to the entries based on frequency */
                cl->cl_nextexe = 1;
+               insert_nextexe(cl);
                cl->cl_pid = cl->cl_mailfd = cl->cl_mailpid = 0;
            }
        }
            
        cl->cl_next = cf->cf_line_base;
        cf->cf_line_base = cl;
+       cl->cl_file = cf;
        Alloc(cl, CL);
     }
     /* free last calloc : unused */
@@ -493,6 +497,8 @@ delete_file(const char *user_name)
     CL *cur_line;
     env_t *env = NULL;
     env_t *cur_env = NULL;
+    struct job *j = NULL;
+    struct job *prev_j = NULL;
 
     file = file_base;
     while ( file != NULL) {
@@ -502,6 +508,25 @@ delete_file(const char *user_name)
            cur_line = file->cf_line_base;
            while ( (line = cur_line) != NULL) {
                cur_line = line->cl_next;
+
+               /* remove line from the lists */
+               if( line->cl_runfreq != 0 ) {
+                   for ( j = freq_base; j != NULL; j = j->j_next )
+                       if ( j->j_line == line ) {
+                           prev_j->j_next = j->j_next;
+                           free(j);
+                           break;
+                       }
+               }
+               else
+                   for ( j = queue_base; j != NULL; j = j->j_next )
+                       if ( j->j_line == line ) {
+                           prev_j->j_next = j->j_next;
+                           free(j);
+                           break;
+                       }
+
+               /* free line itself */
                free(line->cl_shell);
                free(line);
            }
@@ -516,7 +541,7 @@ delete_file(const char *user_name)
        /* file not in list */
        return;
     
-    /* remove file from list */
+    /* remove file from file list */
     if (prev_file == NULL)
        file_base = file->cf_next;
     else
index 596af728c002ec320ad549cb12aa5217a09a1d70..3fdd0640c2dbe2e0a56e2173f65d422dd4f3fbc1 100644 (file)
@@ -22,7 +22,7 @@
  *  `LICENSE' that comes with the fcron source distribution.
  */
 
- /* $Id: database.c,v 1.5 2000-05-30 19:26:21 thib Exp $ */
+ /* $Id: database.c,v 1.6 2000-05-31 19:11:35 thib Exp $ */
 
 #include "fcron.h"
 
@@ -36,60 +36,42 @@ void
 test_jobs(time_t t2)
   /* determine which jobs need to be run, and run them. */
 {
-    CF *file;
-    CL *line;
+    struct job *j = NULL;
 
     debug("Looking for jobs to execute ...");
 
-    for (file = file_base; file; file = file->cf_next) {
-       debug("FILE %s:", file->cf_user);
-
-       for (line = file->cf_line_base; line; line = line->cl_next) {
-
-           if ( (line->cl_nextexe <= t2) && (line->cl_nextexe != 0) ) {
-
-               set_next_exe(line, 0);
-
-               if (--(line->cl_remain) > 0) {
-                   debug("    cl_Remain: %d", line->cl_remain);
-                   continue ;
-               }
-
-               if (line->cl_pid > 0) {
-                   warn("    process already running: %s '%s'", 
-                        file->cf_user,
-                        line->cl_shell
-                       );
-                   line->cl_remain = line->cl_runfreq;
-               } 
-               else {
-                   line->cl_remain = line->cl_runfreq;
-                   
-                   run_job(file, line);
-                   
-               }
-           }
-
-           /* jobs based on timefreq */
-           else if (line->cl_timefreq > 0 && line->cl_remain <= 0 ) {
-
-               line->cl_remain = line->cl_timefreq;
-
-               if (line->cl_pid > 0) {
-                   warn("    process already running: %s '%s'", 
-                        file->cf_user,
-                        line->cl_shell
-                       );
-               } else {
-
-                   run_job(file, line);
-                   
-               }
-           }
-                           
+    /* job based on date & time */
+    for (j=queue_base; (j!=NULL)&&(j->j_line->cl_nextexe <= t2); j=j->j_next){
+       set_next_exe(j->j_line, 0);
+       if (--(j->j_line->cl_remain) > 0) {
+           debug("    cl_Remain: %d", j->j_line->cl_remain);
+           continue ;
+       }
+       if (j->j_line->cl_pid > 0) {
+           warn("    process already running: %s '%s'", 
+                j->j_line->cl_file->cf_user,
+                j->j_line->cl_shell
+               );
+           j->j_line->cl_remain = j->j_line->cl_runfreq;
+       } 
+       else {
+           j->j_line->cl_remain = j->j_line->cl_runfreq;
+           run_job(j->j_line);
+       }
+    }
 
+    /* job based on frequency */
+    for (j=freq_base; (j!=NULL)&&(j->j_line->cl_remain <= 0); j=j->j_next){
+       j->j_line->cl_remain = j->j_line->cl_timefreq;
+       insert_freq(j->j_line);
+       if (j->j_line->cl_pid > 0) {
+           warn("    process already running: %s '%s'", 
+                j->j_line->cl_file->cf_user,
+                j->j_line->cl_shell
+               );
+       } else {
+           run_job(j->j_line);
        }
-       
     }
 
 }
@@ -99,8 +81,7 @@ void
 wait_chld(void)
   /* wait_chld() - check for job completion */
 {
-    CF *file;
-    CL *line;
+    struct job *j = NULL;
     int pid;
     int status;
 
@@ -108,26 +89,17 @@ wait_chld(void)
     debug("wait_chld");
     ///////
 
-    while ( (pid=wait3(&status, WNOHANG, NULL)) > 0 ) {
-
-       for (file = file_base; file; file = file->cf_next) {
-
-           for (line = file->cf_line_base; line && file->cf_running;
-                line = line->cl_next) {
-
-               if (pid < 0 || pid == line->cl_pid) {
-                   end_job(file, line, status);
-                   goto nextloop;
-               }
-               else if ( pid == line->cl_mailpid ) {
-                   end_mailer(line, status);
-                   goto nextloop;
-               }
-
+    while ( (pid = wait3(&status, WNOHANG, NULL)) > 0 ) {
+       for (j = exe_base; j != NULL ; j = j->j_next) {
+           if (pid < 0 || pid == j->j_line->cl_pid) {
+               end_job(j->j_line, status);
+               goto nextloop;
            }
-
-       }
-
+           else if ( pid == j->j_line->cl_mailpid ) {
+               end_mailer(j->j_line, status);
+               goto nextloop;
+           }
+       }       
       nextloop:
     }
 
@@ -138,28 +110,20 @@ void
 wait_all(int *counter)
    /* return after all jobs completion. */
 {
-    CF *file;
-    CL *line;
-    pid_t pid;
+    struct job *j = NULL;
+    int pid;
     int status;
 
     debug("Waiting for all jobs");
 
-    while ( (*counter > 0) && (pid=wait3(&status, 0, NULL)) > 0 ) {
-
-       for (file = file_base; file; file = file->cf_next) {
+    while ( (*counter > 0) && (pid = wait3(&status, 0, NULL)) > 0 ) {
 
-           if (file->cf_running) {
+       for (j = exe_base; j != NULL ; j = j->j_next) {
 
-               for (line = file->cf_line_base; line; line = line->cl_next) {
-
-                   if (pid < 0 || pid == line->cl_pid)
-                       end_job(file, line, status);
-                   else if ( pid == line->cl_mailpid )
-                       end_mailer(line, status);
-
-               }
-           }
+           if (pid < 0 || pid == j->j_line->cl_pid)
+               end_job(j->j_line, status);
+           else if ( pid == j->j_line->cl_mailpid )
+               end_mailer(j->j_line, status);
        }
     }    
 
@@ -285,7 +249,7 @@ goto_non_matching(CL *line, struct tm *ftime)
 
 void 
 set_next_exe(CL *line, char is_new_line)
-  /* set the cl_nextexe of a given CL */
+  /* set the cl_nextexe of a given CL and insert it in the queue */
 {
 
     if (line->cl_timefreq == 0) {
@@ -296,7 +260,6 @@ set_next_exe(CL *line, char is_new_line)
        register int i;
        int max;
 
-
        now = time(NULL);
        ft = localtime(&now);
 
@@ -385,6 +348,8 @@ set_next_exe(CL *line, char is_new_line)
     
        line->cl_nextexe = mktime(&ftime);
 
+       insert_nextexe(line);
+
        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,
@@ -395,41 +360,129 @@ set_next_exe(CL *line, char is_new_line)
 
 }
 
+void
+insert_nextexe(CL *line)
+    /* insert a job based on time and date in the corresponding queue list */
+{
+       struct job *newjob = NULL;
+
+       if (queue_base != NULL) {
+           struct job *j = NULL;
+           struct job *jprev = NULL;
+           struct job *old_entry = NULL;
+
+           j = queue_base;
+           while (j != NULL && (line->cl_nextexe > j->j_line->cl_nextexe)) {
+               if ( j->j_line == line ) {
+                   old_entry = j;
+                   jprev->j_next = j->j_next;
+                   j = jprev;
+               }
+               jprev = j;
+               j = j->j_next;
+           }
+           if (old_entry == NULL) {
+               /* this job wasn't in the queue : we append it */
+               Alloc(newjob, job);
+               newjob->j_line = line;
+           }
+           else
+               /* this job was already in the queue : we move it */
+               newjob = old_entry;
+
+           newjob->j_next = j;
+
+           if (jprev == NULL)
+               queue_base = newjob;
+           else
+               jprev->j_next = newjob;
+
+       }
+       else {
+           /* no job in queue */
+           Alloc(newjob, job);
+           newjob->j_line = line;          
+           queue_base = newjob;
+       }
+
+}
+
+void
+insert_freq(CL *line)
+    /* insert a job based on frequency in the corresponding queue list */
+{
+    struct job *newjob = NULL;
+
+    /* insert job in the queue */
+    if (freq_base != NULL) {
+       struct job *j = NULL;
+       struct job *jprev = NULL;
+       struct job *old_entry = NULL;
+
+       j = freq_base;
+       while (j != NULL && (line->cl_remain > j->j_line->cl_remain)) {
+           if ( j->j_line == line ) {
+               old_entry = j;
+               jprev->j_next = j->j_next;
+               j = jprev;
+           }
+           jprev = j;
+           j = j->j_next;
+       }
+       if (old_entry == NULL) {
+           /* this job wasn't in the queue : we append it */
+           Alloc(newjob, job);
+           newjob->j_line = line;
+       }
+       else
+           /* this job was already in the queue : we move it */
+           newjob = old_entry;
+
+       newjob->j_next = j;
+
+       if (jprev == NULL)
+           freq_base = newjob;
+       else
+           jprev->j_next = newjob;
+    }
+    else {
+       Alloc(newjob, job);
+       newjob->j_line = line;
+       freq_base = newjob;
+    }
+}
 
 long
 time_to_sleep(short lim)
   /* return the time to sleep until next task have to be executed. */
 {
-
-    CF *file;
-    CL *line;
     /* we set tts to a big value, unless some problems can occurs
      * with files without any line */
     time_t tts = lim;
-    time_t cur;
     time_t now;
 
     now = time(NULL);
 
-    for (file = file_base; file; file = file->cf_next) {
-
-       for (line = file->cf_line_base; line; line = line->cl_next) {
-
-           if (line->cl_nextexe > 0)
-               cur = (line->cl_nextexe > now) ? (line->cl_nextexe - now) : 0;
-           else
-               cur = line->cl_remain;
-
-           if (cur < tts)
-               tts = cur;
-
-           if (tts == 0)
-               return 0;
-
-       }
-
+    if (queue_base == NULL && freq_base == NULL)
+       /* no lines : we sleep as much as we can */
+       goto end;
+    else if (queue_base == NULL && freq_base != NULL) {
+       tts = freq_base->j_line->cl_remain;
+       goto end;
+    }
+    else if (queue_base != NULL && freq_base == NULL) {
+       if ( (tts = queue_base->j_line->cl_nextexe - now) < 0 ) tts = 0;
+       goto end;
     }
+           
+    /* we have freq lines and normal lines */
+    if(queue_base->j_line->cl_nextexe - now < freq_base->j_line->cl_remain) {
+       if ( (tts = queue_base->j_line->cl_nextexe - now) < 0 ) tts = 0;
+    }
+    else
+       tts = freq_base->j_line->cl_remain;
 
+  end:
     debug("Time to sleep: %lds", tts);
 
     return tts;
@@ -441,27 +494,20 @@ void
 update_time_remaining(long dt)
   /* update the remaining time of tasks run at a certain frequency */
 {
-    CF *file;
-    CL *line;
 
-    debug("Updating time remaining ...");
-    
-    for (file = file_base; file; file = file->cf_next) {
+    struct job *j = freq_base;
 
-       debug("File %s", file->cf_user);
+    debug("Updating time remaining ...");
     
-       for (line = file->cf_line_base; line; line = line->cl_next) {
-           if (line->cl_timefreq > 0) {
+    for (j=freq_base; j != NULL; j = j->j_next ) {
 
-               if ( (line->cl_remain - dt) >= 0 )
-                   line->cl_remain -= dt;
-               else
-                   line->cl_remain = 0;
+       if ( (j->j_line->cl_remain - dt) >= 0 )
+           j->j_line->cl_remain -= dt;
+       else
+           j->j_line->cl_remain = 0;
 
-               debug("  '%s' cl_remain = %d", line->cl_shell,
-                     line->cl_remain);
-           }
-       }
+       debug("  '%s' cl_remain = %d", j->j_line->cl_shell,
+             j->j_line->cl_remain);
 
     }
   
diff --git a/fcron.c b/fcron.c
index 18b632f0ba2175eea91e3dbc018b74b64468c5f0..f2b08e9044cb8be68a9033e6c228204adf8dd1dd 100644 (file)
--- a/fcron.c
+++ b/fcron.c
  *  `LICENSE' that comes with the fcron source distribution.
  */
 
- /* $Id: fcron.c,v 1.8 2000-05-30 19:26:28 thib Exp $ */
+ /* $Id: fcron.c,v 1.9 2000-05-31 19:11:40 thib Exp $ */
 
 #include "fcron.h"
 
-char rcs_info[] = "$Id: fcron.c,v 1.8 2000-05-30 19:26:28 thib Exp $";
+char rcs_info[] = "$Id: fcron.c,v 1.9 2000-05-31 19:11:40 thib Exp $";
 
 void main_loop(void);
 void info(void);
 void usage(void);
-void xexit(int exit_value);
 void sighup_handler(int x);
 void sigterm_handler(int x);
 void sigchild_handler(int x);
@@ -39,15 +38,27 @@ int parseopt(int argc, char *argv[]);
 void get_lock(void);
 
 
+/* command line options */
 char debug_opt = DEBUG;       /* set to 1 if we are in debug mode */
 char foreground = FOREGROUND; /* set to 1 when we are on foreground, else 0 */
-char  *cdir = FCRONTABS;       /* the dir where are stored users' fcrontabs */
+char  *cdir = FCRONTABS;      /* the dir where are stored users' fcrontabs */
+
+/* process identity */
 int daemon_uid;                 
 pid_t daemon_pid;               
 char *prog_name = NULL;         
-char sig_conf = 0;             /* is 1 when we got a SIGHUP */ 
+
+/* have we got a signal ? */
+char sig_conf = 0;            /* is 1 when we got a SIGHUP */ 
 char sig_chld = 0;            /* is 1 when we got a SIGCHLD */  
-CF *file_base;                /* point to the first file of the list */
+
+/* jobs database */
+struct CF *file_base;         /* point to the first file of the list */
+struct job *queue_base;       /* ordered list of normal jobs to be run */
+struct job *serial_base;      /* ordered list of job to be run one by one */
+struct job *freq_base;        /* ordered list of jobs based on frequency */
+struct job *exe_base;         /* jobs which are executed */
+
 time_t t1;                    /* the time at which sleep began */
 
 
@@ -494,11 +505,10 @@ void main_loop()
                if (sig_conf == 1)
                    /* update configuration */
                    synchronize_dir(".");
-               else {
+               else
                    /* reload all configuration */
-                   update_time_remaining(dt);              
                    reload_all(".");
-               }               
+
                sig_conf = 0;
            }
 
diff --git a/fcron.h b/fcron.h
index b419203e82a5335783e4fb97748090043701b06f..5068282eeb8d0e827547656949edd317377fe518 100644 (file)
--- a/fcron.h
+++ b/fcron.h
@@ -21,7 +21,7 @@
  *  `LICENSE' that comes with the fcron source distribution.
  */
 
- /* $Id: fcron.h,v 1.4 2000-05-30 19:26:48 thib Exp $ */
+ /* $Id: fcron.h,v 1.5 2000-05-31 19:11:42 thib Exp $ */
 
 #ifndef __FCRONH__
 #define __FCRONH__
@@ -44,6 +44,10 @@ extern pid_t daemon_pid;
 extern char *prog_name;
 extern char sig_hup;
 extern CF *file_base;
+extern struct job *queue_base;
+extern struct job *serial_base;
+extern struct job *freq_base;
+extern struct job *exe_base;
 /* end of global variables */
 
 
@@ -78,6 +82,8 @@ extern void wait_chld(void);
 extern void wait_all(int *counter);
 extern time_t time_to_sleep(short lim);
 extern void set_next_exe(CL *line, char is_new_line);
+extern void insert_nextexe(CL *line);
+extern void insert_freq(CL *line);
 extern void update_time_remaining(long dt);
 /* end of database.c */
 
@@ -89,8 +95,8 @@ extern void save_file(CF *file_name, char *path);
 /* end of conf.c */
 
 /* job.c */
-extern void run_job(CF *file, CL *line);
-extern void end_job(CF *file, CL *line, int status);
+extern void run_job(CL *line);
+extern void end_job(CL *line, int status);
 extern void end_mailer(CL *line, int status);
 /* end of job.c */
 
index 3ffab6c691933c514dd8eca000a5153c7197dc10..093b55c63366a1f45fe9fbb4e164875dea4147d0 100644 (file)
--- a/global.h
+++ b/global.h
  *  `LICENSE' that comes with the fcron source distribution.
  */
 
- /* $Id: global.h,v 1.4 2000-05-30 19:27:28 thib Exp $ */
+ /* $Id: global.h,v 1.5 2000-05-31 19:11:44 thib Exp $ */
+
+
+/* 
+   WARNING : this file should not be modified.
+   Compilation's options are in config.h
+*/
 
 #ifndef __GLOBALH__
 #define __GLOBALH__
 #include <unistd.h>
 #include <fcntl.h>
 
-#include "bitstring.h"         
-
 #include "config.h"
+#include "bitstring.h"         
+#include "option.h"
 
 
-
-/* none configurable constants */
-#define FILEVERSION "001"  /* syntax's version of fcrontabs : 
+#define FILEVERSION "002"  /* syntax's version of fcrontabs : 
                            * must have a length of 3 characters */
 
 
@@ -69,6 +73,7 @@
 
 #define debug if(debug_opt) Debug
 
+
 typedef struct env_t {
     char         *e_name;       /* env name                             */
     char         *e_val;        /* env value                            */
@@ -80,6 +85,7 @@ typedef struct CF {
     struct CL    *cf_line_base;
     char        *cf_user;      /* user-name                            */
     char         *cf_mailto;    /* mail output's to mail_user           */
+    short int   cf_mailpos;    /* 'empty mail file' size               */
     struct env_t *cf_env_base;  /* list of all env variables to set     */
     int                 cf_running;    /* number of jobs running               */
 } CF;
@@ -88,11 +94,12 @@ typedef struct CF {
  *   because some tests made are dependent to that order */
 typedef struct CL {
     struct CL    *cl_next;
+    struct CF    *cl_file;      /* the file in which the line is        */
+    char         option;        /* options for that line (see option.h) */
     char        *cl_shell;     /* shell command                        */
     pid_t       cl_pid;        /* running pid, 0, or armed (-1)        */
     pid_t       cl_mailpid;    /* mailer pid or 0                      */
     int                 cl_mailfd;     /* running pid is for mail              */
-    int                 cl_mailpos;    /* 'empty file' size                    */
     /* see bitstring(3) man page for more details */
     bitstr_t    bit_decl(cl_mins, 60);  /* 0-59                        */
     bitstr_t    bit_decl(cl_hrs, 24);  /* 0-23                         */
@@ -105,6 +112,10 @@ typedef struct CL {
     time_t       cl_nextexe;     /* time and date of the next execution */
 } CL;
 
+typedef struct job {
+    struct CL    *j_line;
+    struct job   *j_next;
+} job;
 
 
 #endif /* __GLOBALH__ */
diff --git a/job.c b/job.c
index e6cea3753e89fb81f6b5f43a61cf876abf92fe6c..32c5574b4e1ec4249acfe87252836f6241f3730a 100644 (file)
--- a/job.c
+++ b/job.c
  *  `LICENSE' that comes with the fcron source distribution.
  */
 
- /* $Id: job.c,v 1.5 2000-05-30 19:27:30 thib Exp $ */
+ /* $Id: job.c,v 1.6 2000-05-31 19:11:47 thib Exp $ */
 
 #include "fcron.h"
 
 int temp_file(void);
 void xwrite(int fd, char *string);
-void launch_mailer(CF *file, CL *line);
+void launch_mailer(CL *line);
 int change_user(const char *user, short dochdir);
 
 
@@ -72,7 +72,7 @@ change_user(const char *user, short dochdir)
 
 
 void 
-run_job(CF *file, CL *line)
+run_job(CL *line)
     /* fork(), redirect outputs to a temp file, and execl() the task */ 
 {
 
@@ -80,17 +80,27 @@ run_job(CF *file, CL *line)
     char *shell = NULL;
     char *home = NULL;
     env_t *env = NULL;
+    struct job *j = NULL;
 
     /* create temporary file for stdout and stderr of the job */
     line->cl_mailfd = temp_file();
 
     /* write mail header */
     xwrite(line->cl_mailfd,"To: ");
-    xwrite(line->cl_mailfd, file->cf_user);
+    xwrite(line->cl_mailfd, line->cl_file->cf_user);
     xwrite(line->cl_mailfd, "\nSubject: Output of fcron job: '");
     xwrite(line->cl_mailfd, line->cl_shell);
     xwrite(line->cl_mailfd,"'\n\n");
-    line->cl_mailpos = lseek(line->cl_mailfd, 0, SEEK_END);
+    if ( ! line->cl_file->cf_mailpos ) 
+       line->cl_file->cf_mailpos = ( lseek(line->cl_mailfd, 0, SEEK_END)
+           - strlen(line->cl_shell) );
+
+
+    /* append job to the list of executed job */
+    Alloc(j, job);
+    j->j_line = line;
+    j->j_next = exe_base;
+    exe_base = j;
 
     switch ( pid = fork() ) {
 
@@ -98,7 +108,7 @@ run_job(CF *file, CL *line)
        /* child */
 
        foreground = 0;
-       if (change_user(file->cf_user, 1) < 0)
+       if (change_user(line->cl_file->cf_user, 1) < 0)
            return ;
 
        /* stdin is already /dev/null, setup stdout and stderr */
@@ -107,11 +117,14 @@ run_job(CF *file, CL *line)
        if ( close(2) != 0 )
            die_e("Can't close file descriptor %d",2);
 
-       if ( file->cf_mailto != NULL && strcmp(file->cf_mailto, "") == 0 ) {
+       if ( line->cl_file->cf_mailto != NULL &&
+            strcmp(line->cl_file->cf_mailto, "") == 0 ) {
+
            if ( close(line->cl_mailfd) != 0 )
                die_e("Can't close file descriptor %d", line->cl_mailfd);
            if ( (line->cl_mailfd = open("/dev/null", O_RDWR)) < 0 )
                die_e("open: /dev/null:");
+
        }
 
        if (dup2(line->cl_mailfd, 1) != 1 || dup2(line->cl_mailfd, 2) != 2)
@@ -123,7 +136,7 @@ run_job(CF *file, CL *line)
        xcloselog();
 
        /* set env variables */
-       for ( env = file->cf_env_base; env; env = env->e_next)
+       for ( env = line->cl_file->cf_env_base; env; env = env->e_next)
            if ( setenv(env->e_name, env->e_val, 1) != 0 )
                error("could not setenv()");
 
@@ -169,10 +182,10 @@ run_job(CF *file, CL *line)
        line->cl_pid = pid;
 
        ////////////
-       debug("   cf_running: %d", file->cf_running);
+       debug("   cf_running: %d", line->cl_file->cf_running);
        ///////////
 
-       file->cf_running += 1;
+       line->cl_file->cf_running += 1;
 
        explain("  Job `%s' started (pid %d)", line->cl_shell, line->cl_pid);
 
@@ -181,7 +194,7 @@ run_job(CF *file, CL *line)
 }
 
 void 
-end_job(CF *file, CL *line, int status)
+end_job(CL *line, int status)
     /* if task have made some output, mail it to user */
 {
 
@@ -192,8 +205,10 @@ end_job(CF *file, CL *line, int status)
     debug("   end_job");
 //////
 
-    if ( lseek(line->cl_mailfd, 0, SEEK_END) > line->cl_mailpos ) {
-       if ( file->cf_mailto != NULL && file->cf_mailto[0] == '\0' )
+    if ( ( lseek(line->cl_mailfd, 0, SEEK_END) - strlen (line->cl_shell) )
+        > line->cl_file->cf_mailpos ) {
+       if ( line->cl_file->cf_mailto != NULL &&
+            line->cl_file->cf_mailto[0] == '\0' )
            /* there is a mail output, but it will not be mail */
            mail_output = 2;
        else
@@ -216,7 +231,7 @@ end_job(CF *file, CL *line, int status)
     else /* is this possible? */
        error("Job `%s' terminated abnormally %s", line->cl_shell, m);
 
-    if (mail_output == 1) launch_mailer(file, line);
+    if (mail_output == 1) launch_mailer(line);
 
     /* if MAILTO is "", temp file is already closed */
     if ( mail_output != 2 && close(line->cl_mailfd) != 0 )
@@ -225,14 +240,14 @@ end_job(CF *file, CL *line, int status)
     line->cl_pid = 0;
 
     ////////////
-    debug("    cf_running: %d", file->cf_running);
+    debug("    cf_running: %d", line->cl_file->cf_running);
 
-    file->cf_running -= 1;
+    line->cl_file->cf_running -= 1;
 
 }
 
 void
-launch_mailer(CF *file, CL *line)
+launch_mailer(CL *line)
     /* mail the output of a job to user */
 {
     char *mailto = NULL;
@@ -257,11 +272,11 @@ launch_mailer(CF *file, CL *line)
        xcloselog();
 
        /* determine which will be the mail receiver */
-       if ( (mailto = file->cf_mailto) == NULL )
-           mailto = file->cf_user;
+       if ( (mailto = line->cl_file->cf_mailto) == NULL )
+           mailto = line->cl_file->cf_user;
 
        /* change permissions */
-       if (change_user(file->cf_user, 1) < 0)
+       if (change_user(line->cl_file->cf_user, 1) < 0)
            return ;
 
        /* run sendmail with mail file as standard input */