From: thib Date: Wed, 31 May 2000 19:11:15 +0000 (+0000) Subject: support of queues X-Git-Tag: ver1564~638 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f8e83cd3f7a1c28de573aa0654520e63a9fe64e4;p=fcron support of queues --- diff --git a/conf.c b/conf.c index 5f94527..37877ee 100644 --- 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 diff --git a/database.c b/database.c index 596af72..3fdd064 100644 --- a/database.c +++ b/database.c @@ -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 18b632f..f2b08e9 100644 --- a/fcron.c +++ b/fcron.c @@ -21,16 +21,15 @@ * `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 b419203..5068282 100644 --- 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 */ diff --git a/global.h b/global.h index 3ffab6c..093b55c 100644 --- a/global.h +++ b/global.h @@ -21,7 +21,13 @@ * `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__ @@ -46,14 +52,12 @@ #include #include -#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 e6cea37..32c5574 100644 --- a/job.c +++ b/job.c @@ -22,13 +22,13 @@ * `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 */