tag 155109 patch
thanks
#155109 - cron: sendmail can time out during extended interval of job execution
http://bugs.debian.org./155109
I'm including patches for cron-3 and cron-4 which effect the saving of
job output to a tempfile rather than a potentially-longlived pipe to
sendmail. That also allowed me to output a warning when a job fails.
diff -u cron-3.0pl1/debian/changelog cron-3.0pl1/debian/changelog
--- cron-3.0pl1/debian/changelog
+++ cron-3.0pl1/debian/changelog
@@ -1,3 +1,11 @@
+cron (3.0pl1-104.1) unstable; urgency=low
+
+ * Non-maintainer upload.
+ * do_command.c: Call log_it rather than fprintf when execing a user command
+ fails (Closes: 443615).
+
+ -- Justin Pryzby <[EMAIL PROTECTED]> Thu, 27 Mar 2008 09:04:26 -0400
+
cron (3.0pl1-104) unstable; urgency=low
* Discard errors from df in the standard daily cron task to prevent errors
diff -u cron-3.0pl1/debian/NEWS cron-3.0pl1/debian/NEWS
--- cron-3.0pl1/debian/NEWS
+++ cron-3.0pl1/debian/NEWS
@@ -1,3 +1,10 @@
+cron (3.0pl1-104.1) unstable; urgency=low
+
+ Debian cron now outputs a warning to the logfile and to the mail when
+ commands fail.
+
+ -- Justin Pryzby <[EMAIL PROTECTED]> Thu, 27 Mar 2008 15:29:32 -0400
+
cron (3.0pl1-74) unstable; urgency=low
The checksecurity script is no longer included with the cron package:
@@ -9 +15,0 @@
-
diff -u cron-3.0pl1/do_command.c cron-3.0pl1/do_command.c
--- cron-3.0pl1/do_command.c
+++ cron-3.0pl1/do_command.c
@@ -111,12 +111,21 @@
}
+/*
+ * CROND
+ * - cron (runs child_process);
+ * - cron (runs exec sh -c 'tab entry');
+ * - cron (writes any %-style stdin to the command);
+ * - mail (popen writes any stdout to mailcmd);
+ */
+
static void
child_process(e, u)
entry *e;
user *u;
{
- int stdin_pipe[2], stdout_pipe[2];
+ int stdin_pipe[2];
+ FILE *out;
register char *input_data;
char *usernm, *mailto;
int children = 0;
@@ -179,7 +188,11 @@
/* create some pipes to talk to our future child
*/
pipe(stdin_pipe); /* child's stdin */
- pipe(stdout_pipe); /* child's stdout */
+ /* child's stdout */
+ if ((out=tmpfile())==NULL) {
+ log_it("CRON",getpid(),"error","create tmpfile");
+ exit(ERROR_EXIT);
+ }
/* since we are a forked process, we can diddle the command string
* we were passed -- nobody else is going to use it again, right?
@@ -270,7 +283,6 @@
* appropriate circumstances.
*/
close(stdin_pipe[WRITE_PIPE]);
- close(stdout_pipe[READ_PIPE]);
/* grandchild process. make std{in,out} be the ends of
* pipes opened by our daddy; make stderr go to stdout.
@@ -278,14 +290,14 @@
/* Closes are unnecessary -- let dup2() do it */
/* close(STDIN) */; dup2(stdin_pipe[READ_PIPE], STDIN);
- /* close(STDOUT) */; dup2(stdout_pipe[WRITE_PIPE], STDOUT);
+ dup2(fileno(out), STDOUT);
/* close(STDERR)*/; dup2(STDOUT, STDERR);
/* close the pipes we just dup'ed. The resources will remain.
*/
close(stdin_pipe[READ_PIPE]);
- close(stdout_pipe[WRITE_PIPE]);
+ // Don't do this: fclose(out);
/* set our login universe. Do this in the grandchild
* so that the child can invoke /usr/lib/sendmail
@@ -364,7 +376,6 @@
* grandchild process...
*/
close(stdin_pipe[READ_PIPE]);
- close(stdout_pipe[WRITE_PIPE]);
/*
* write, to the pipe connected to child's stdin, any input specified
@@ -385,11 +396,6 @@
Debug(DPROC, ("[%d] child2 sending data to grandchild\n",
getpid()))
- /* close the pipe we don't use, since we inherited it and
- * are part of its reference count now.
- */
- close(stdout_pipe[READ_PIPE]);
-
/* translation:
* \% -> %
* % -> \n
@@ -439,165 +445,12 @@
Debug(DPROC, ("[%d] child reading output from grandchild\n", getpid()))
- /*local*/{
- register FILE *in = fdopen(stdout_pipe[READ_PIPE], "r");
- register int ch = getc(in);
-
- if (ch != EOF) {
- register FILE *mail;
- register int bytes = 1;
- int status = 0;
-
- Debug(DPROC|DEXT,
- ("[%d] got data (%x:%c) from grandchild\n",
- getpid(), ch, ch))
-
- /* get name of recipient. this is MAILTO if set to a
- * valid local username; USER otherwise.
- */
- if (mailto) {
- /* MAILTO was present in the environment
- */
- if (!*mailto) {
- /* ... but it's empty. set to NULL
- */
- mailto = NULL;
- }
- } else {
- /* MAILTO not present, set to USER.
- */
- mailto = usernm;
- }
-
- /* if we are supposed to be mailing, MAILTO will
- * be non-NULL. only in this case should we set
- * up the mail command and subjects and stuff...
- */
-
- if (mailto) {
- register char **env;
- char **jobenv = build_env(e->envp);
- auto char mailcmd[MAX_COMMAND];
- auto char hostname[MAXHOSTNAMELEN];
- char *content_type =
env_get("CONTENT_TYPE",jobenv),
- *content_transfer_encoding =
env_get("CONTENT_TRANSFER_ENCODING",jobenv);
-
-
- (void) gethostname(hostname, MAXHOSTNAMELEN);
- (void) snprintf(mailcmd, sizeof(mailcmd),
- MAILARGS, MAILCMD, mailto);
- if (!(mail = cron_popen(mailcmd, "w", e))) {
- perror(MAILCMD);
- (void) _exit(ERROR_EXIT);
- }
- fprintf(mail, "From: root (Cron Daemon)\n");
- fprintf(mail, "To: %s\n", mailto);
- fprintf(mail, "Subject: Cron <[EMAIL
PROTECTED]> %s\n",
- usernm, first_word(hostname, "."),
- e->cmd);
-# if defined(MAIL_DATE)
- fprintf(mail, "Date: %s\n",
- arpadate(&StartTime));
-# endif /* MAIL_DATE */
- if ( content_type == 0L ) {
- fprintf(mail, "Content-Type:
text/plain; charset=%s\n",
- cron_default_mail_charset
- );
- } else {
- /* user specified Content-Type header.
- * disallow new-lines for security reasons
- * (else users could specify arbitrary mail
headers!)
- */
- char *nl=content_type;
- size_t ctlen = strlen(content_type);
-
- while( (*nl != '\0')
- && ((nl=strchr(nl,'\n')) != 0L)
- && (nl < (content_type+ctlen))
- ) *nl = ' ';
- fprintf(mail,"Content-Type: %s\n",
content_type);
- }
- if ( content_transfer_encoding != 0L ) {
- char *nl=content_transfer_encoding;
- size_t ctlen =
strlen(content_transfer_encoding);
- while( (*nl != '\0')
- && ((nl=strchr(nl,'\n')) != 0L)
- && (nl <
(content_transfer_encoding+ctlen))
- ) *nl = ' ';
-
-
fprintf(mail,"Content-Transfer-Encoding: %s\n", content_transfer_encoding);
- }
-
-
- for (env = e->envp; *env; env++)
- fprintf(mail, "X-Cron-Env: <%s>\n",
- *env);
- fprintf(mail, "\n");
-
- /* this was the first char from the pipe
- */
- putc(ch, mail);
- }
-
- /* we have to read the input pipe no matter whether
- * we mail or not, but obviously we only write to
- * mail pipe if we ARE mailing.
- */
-
- while (EOF != (ch = getc(in))) {
- bytes++;
- if (mailto)
- putc(ch, mail);
- }
-
- /* only close pipe if we opened it -- i.e., we're
- * mailing...
- */
-
- if (mailto) {
- Debug(DPROC, ("[%d] closing pipe to mail\n",
- getpid()))
- /* Note: the pclose will probably see
- * the termination of the grandchild
- * in addition to the mail process, since
- * it (the grandchild) is likely to exit
- * after closing its stdout.
- */
- status = cron_pclose(mail);
- }
-
- /* if there was output and we could not mail it,
- * log the facts so the poor user can figure out
- * what's going on.
- */
- if (mailto && status) {
- char buf[MAX_TEMPSTR];
-
- snprintf(buf, MAX_TEMPSTR,
- "mailed %d byte%s of output but got status 0x%04x\n",
- bytes, (bytes==1)?"":"s",
- status);
- log_it(usernm, getpid(), "MAIL", buf);
- }
-
- } /*if data from grandchild*/
-
- if (log_level >= 2) {
- char *x = mkprints((u_char *)e->cmd, strlen(e->cmd));
-
- log_it(usernm, getpid(), "END", x);
- free(x);
- }
-
- Debug(DPROC, ("[%d] got EOF from grandchild\n", getpid()))
-
- fclose(in); /* also closes stdout_pipe[READ_PIPE] */
- }
-
/* wait for children to die.
*/
+ int status=0;
for (; children > 0; children--)
{
+ char msg[256];
WAIT_T waiter;
PID_T pid;
@@ -605,16 +458,159 @@
getpid(), children))
pid = wait(&waiter);
if (pid < OK) {
- Debug(DPROC, ("[%d] no more grandchildren--mail
written?\n",
- getpid()))
+ Debug(DPROC, ("[%d] no more grandchildren\n", getpid()))
+ break;
+ }
+ Debug(DPROC, ("[%d] grandchild #%d finished, status=%04x\n",
+ getpid(), pid, waiter))
+
+ if (WIFEXITED(waiter) && WEXITSTATUS(waiter)) {
+ status=waiter;
+ snprintf(msg, 256, "grandchild #%d failed with exit
status %d", pid, WEXITSTATUS(waiter));
+ log_it("CRON",getpid(),"error",msg);
+ } else if (WIFSIGNALED(waiter)) {
+ status=waiter;
+ snprintf(msg, 256, "grandchild #%d terminated by signal
%d%s",
+ pid, WTERMSIG(waiter),
+ WCOREDUMP(waiter)?", dumped core":"");
+ log_it("CRON",getpid(),"error",msg);
+ }
+ }
+
+// Finally, send any output of the command to the mailer; also, alert
+// the user if their job failed. Avoid popening the mailcmd until now
+// since sendmail may time out, and to write info about the exit
+// status.
+
+ long pos;
+
+ fseek(out, 0, SEEK_END);
+ pos=ftell(out);
+ fseek(out, 0, SEEK_SET);
+
+ Debug(DPROC|DEXT, ("[%d] got %ld bytes data from grandchild tmpfile\n",
+ getpid(), (long)pos))
+ if (pos==0 && status==0) return;
+
+ // get name of recipient.
+ if (mailto==NULL /*|| !*mailto*/) mailto=usernm;
+ else if (!*mailto) mailto=NULL;
+
+ register FILE *mail;
+ register int bytes = 1;
+
+ register char **env;
+ char **jobenv = build_env(e->envp);
+ auto char mailcmd[MAX_COMMAND];
+ auto char hostname[MAXHOSTNAMELEN];
+ char *content_type = env_get("CONTENT_TYPE",jobenv),
+ *content_transfer_encoding =
env_get("CONTENT_TRANSFER_ENCODING",jobenv);
+
+ (void) gethostname(hostname, MAXHOSTNAMELEN);
+ (void) snprintf(mailcmd, sizeof(mailcmd),
+ MAILARGS, MAILCMD, mailto);
+ if (!(mail = cron_popen(mailcmd, "w", e))) {
+ perror(MAILCMD);
+ (void) _exit(ERROR_EXIT);
+ }
+ fprintf(mail, "From: root (Cron Daemon)\n");
+ fprintf(mail, "To: %s\n", mailto);
+ fprintf(mail, "Subject: Cron <[EMAIL PROTECTED]> %s%s\n",
+ usernm, first_word(hostname, "."),
+ e->cmd, status?" (failed)":"");
+# if defined(MAIL_DATE)
+ fprintf(mail, "Date: %s\n",
+ arpadate(&StartTime));
+# endif /* MAIL_DATE */
+ if ( content_type == 0L ) {
+ fprintf(mail, "Content-Type: text/plain; charset=%s\n",
+ cron_default_mail_charset
+ );
+ } else {
+ /* user specified Content-Type header.
+ * disallow new-lines for security reasons
+ * (else users could specify arbitrary mail headers!)
+ */
+ char *nl=content_type;
+ size_t ctlen = strlen(content_type);
+
+ while( (*nl != '\0')
+ && ((nl=strchr(nl,'\n')) != 0L)
+ && (nl < (content_type+ctlen))
+ ) *nl = ' ';
+ fprintf(mail,"Content-Type: %s\n", content_type);
+ }
+ if ( content_transfer_encoding != 0L ) {
+ char *nl=content_transfer_encoding;
+ size_t ctlen = strlen(content_transfer_encoding);
+ while( (*nl != '\0')
+ && ((nl=strchr(nl,'\n')) != 0L)
+ && (nl < (content_transfer_encoding+ctlen))
+ ) *nl = ' ';
+
+ fprintf(mail,"Content-Transfer-Encoding: %s\n",
content_transfer_encoding);
+ }
+
+ for (env = e->envp; *env; env++)
+ fprintf(mail, "X-Cron-Env: <%s>\n",
+ *env);
+ fputc('\n', mail);
+
+ if (WIFEXITED(status)) {
+ status=WEXITSTATUS(status);
+ fprintf(mail, "command failed with exit status %d\n\n", status);
+ } else if (WIFSIGNALED(status)) {
+ fprintf(mail, "command terminated by signal %d%s\n\n",
+ WTERMSIG(status),
+ WCOREDUMP(status)?", dumped core":"");
+ }
+
+// Finally, send any output of the command to the mailer; also, alert
+// the user if their job failed. Avoid popening the mailcmd until now
+// since sendmail may time out, and to write info about the exit
+// status.
+
+ for ( ; 1; ) {
+ char buf[1<<12];
+ int ret, remain;
+ if ((ret=fread(buf, 1, sizeof(buf), out))==0) break;
+ for (remain=ret; remain!=0; ) {
+ ret=fwrite(buf, 1, remain, mail);
+ if (ret>0) { remain-=ret; continue; }
+ // XXX error
break;
}
- Debug(DPROC, ("[%d] grandchild #%d finished, status=%04x",
- getpid(), pid, WEXITSTATUS(waiter)))
- if (WIFSIGNALED(waiter) && WCOREDUMP(waiter))
- Debug(DPROC, (", dumped core"))
- Debug(DPROC, ("\n"))
}
+
+ Debug(DPROC, ("[%d] closing pipe to mail\n", getpid()))
+ status = cron_pclose(mail);
+
+ /* if there was output and we could not mail it,
+ * log the facts so the poor user can figure out
+ * what's going on.
+ */
+ if (status) {
+ char buf[MAX_TEMPSTR];
+ snprintf(buf, MAX_TEMPSTR,
+ "mailed %d byte%s of output; "
+ "but got status 0x%04x, "
+ "\n",
+ bytes, (bytes==1)?"":"s", status);
+ log_it(usernm, getpid(), "MAIL", buf);
+ }
+
+ if (ferror(out)) {
+ log_it(usernm, getpid(), "MAIL", "stream error reading output");
+ }
+
+ fclose(out);
+
+ if (log_level >= 2) {
+ char *x = mkprints((u_char *)e->cmd, strlen(e->cmd));
+ log_it(usernm, getpid(), "END", x);
+ free(x);
+ }
+
#if defined(USE_PAM)
pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT);
retcode = pam_close_session(pamh, PAM_SILENT);
diff -u cron-3.0pl1/popen.c cron-3.0pl1/popen.c
--- cron-3.0pl1/popen.c
+++ cron-3.0pl1/popen.c
@@ -167,7 +167,7 @@
FILE *iop;
{
register int fdes;
- int omask;
+ sigset_t omask, mask;
WAIT_T stat_loc;
PID_T pid;
@@ -180,8 +180,12 @@
(void)fclose(iop);
- omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
- while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1)
- ;
- (void)sigsetmask(omask);
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGQUIT);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGHUP);
+ sigprocmask(SIG_BLOCK, &mask, &omask);
+ pid=waitpid(pids[fdes], &stat_loc, 0);
+ sigprocmask(SIG_SETMASK, &omask, NULL);
pids[fdes] = 0;
- return (pid == -1 ? -1 : WEXITSTATUS(stat_loc));
+ if (pid==-1 || !WIFEXITED(stat_loc)) return -1;
+ return WEXITSTATUS(stat_loc);
}
Binary files cron-4.1.orig/cron and cron-4.1/cron differ
Binary files cron-4.1.orig/cron.o and cron-4.1/cron.o differ
Binary files cron-4.1.orig/crontab and cron-4.1/crontab differ
Binary files cron-4.1.orig/crontab.o and cron-4.1/crontab.o differ
Binary files cron-4.1.orig/database.o and cron-4.1/database.o differ
diff -Nur cron-4.1.orig/do_command.c cron-4.1/do_command.c
--- cron-4.1.orig/do_command.c 2008-03-27 16:12:51.000000000 -0400
+++ cron-4.1/do_command.c 2008-03-27 20:11:35.000000000 -0400
@@ -60,9 +60,18 @@
Debug(DPROC, ("[%ld] main process returning to work\n",(long)getpid()))
}
+/*
+ * CROND
+ * - cron (runs child_process);
+ * - cron (runs exec sh -c 'tab entry');
+ * - cron (writes any %-style stdin to the command);
+ * - mail (popen writes any stdout to mailcmd);
+ */
+
static void
child_process(entry *e, user *u) {
- int stdin_pipe[2], stdout_pipe[2];
+ int stdin_pipe[2];
+ FILE *out;
char *input_data, *usernm, *mailto;
int children = 0;
@@ -95,7 +104,11 @@
/* create some pipes to talk to our future child
*/
pipe(stdin_pipe); /* child's stdin */
- pipe(stdout_pipe); /* child's stdout */
+ /* child's stdout */
+ if ((out=tmpfile())==NULL) {
+ log_it("CRON",getpid(),"error","create tmpfile");
+ exit(ERROR_EXIT);
+ }
/* since we are a forked process, we can diddle the command string
* we were passed -- nobody else is going to use it again, right?
@@ -172,7 +185,6 @@
* appropriate circumstances.
*/
close(stdin_pipe[WRITE_PIPE]);
- close(stdout_pipe[READ_PIPE]);
/* grandchild process. make std{in,out} be the ends of
* pipes opened by our daddy; make stderr go to stdout.
@@ -181,11 +193,9 @@
dup2(stdin_pipe[READ_PIPE], STDIN);
close(stdin_pipe[READ_PIPE]);
}
- if (stdout_pipe[WRITE_PIPE] != STDOUT) {
- dup2(stdout_pipe[WRITE_PIPE], STDOUT);
- close(stdout_pipe[WRITE_PIPE]);
- }
+ dup2(fileno(out), STDOUT);
dup2(STDOUT, STDERR);
+ // Don't do this: fclose(out);
/* set our directory, uid and gid. Set gid first, since once
* we set uid, we've lost root privledges.
@@ -288,7 +298,6 @@
* grandchild process...
*/
close(stdin_pipe[READ_PIPE]);
- close(stdout_pipe[WRITE_PIPE]);
/*
* write, to the pipe connected to child's stdin, any input specified
@@ -310,11 +319,6 @@
Debug(DPROC, ("[%ld] child2 sending data to grandchild\n",
(long)getpid()))
- /* close the pipe we don't use, since we inherited it and
- * are part of its reference count now.
- */
- close(stdout_pipe[READ_PIPE]);
-
/* translation:
* \% -> %
* % -> \n
@@ -366,128 +370,11 @@
Debug(DPROC, ("[%ld] child reading output from grandchild\n",
(long)getpid()))
- /*local*/{
- FILE *in = fdopen(stdout_pipe[READ_PIPE], "r");
- int ch = getc(in);
-
- if (ch != EOF) {
- FILE *mail;
- int bytes = 1;
- int status = 0;
-
- Debug(DPROC|DEXT,
- ("[%ld] got data (%x:%c) from grandchild\n",
- (long)getpid(), ch, ch))
-
- /* get name of recipient. this is MAILTO if set to a
- * valid local username; USER otherwise.
- */
- if (mailto) {
- /* MAILTO was present in the environment
- */
- if (!*mailto) {
- /* ... but it's empty. set to NULL
- */
- mailto = NULL;
- }
- } else {
- /* MAILTO not present, set to USER.
- */
- mailto = usernm;
- }
-
- /* if we are supposed to be mailing, MAILTO will
- * be non-NULL. only in this case should we set
- * up the mail command and subjects and stuff...
- */
-
- if (mailto && safe_p(usernm, mailto)) {
- char **env;
- char mailcmd[MAX_COMMAND];
- char hostname[MAXHOSTNAMELEN];
-
- gethostname(hostname, MAXHOSTNAMELEN);
- if (strlens(MAILFMT, MAILARG, NULL) + 1
- >= sizeof mailcmd) {
- fprintf(stderr, "mailcmd too long\n");
- (void) _exit(ERROR_EXIT);
- }
- (void)sprintf(mailcmd, MAILFMT, MAILARG);
- if (!(mail = cron_popen(mailcmd, "w", e->pwd)))
{
- perror(mailcmd);
- (void) _exit(ERROR_EXIT);
- }
- fprintf(mail, "From: root (Cron Daemon)\n");
- fprintf(mail, "To: %s\n", mailto);
- fprintf(mail, "Subject: Cron <[EMAIL
PROTECTED]> %s\n",
- usernm, first_word(hostname, "."),
- e->cmd);
-#ifdef MAIL_DATE
- fprintf(mail, "Date: %s\n",
- arpadate(&StartTime));
-#endif /*MAIL_DATE*/
- for (env = e->envp; *env; env++)
- fprintf(mail, "X-Cron-Env: <%s>\n",
- *env);
- fprintf(mail, "\n");
-
- /* this was the first char from the pipe
- */
- putc(ch, mail);
- }
-
- /* we have to read the input pipe no matter whether
- * we mail or not, but obviously we only write to
- * mail pipe if we ARE mailing.
- */
-
- while (EOF != (ch = getc(in))) {
- bytes++;
- if (mailto)
- putc(ch, mail);
- }
-
- /* only close pipe if we opened it -- i.e., we're
- * mailing...
- */
-
- if (mailto) {
- Debug(DPROC, ("[%ld] closing pipe to mail\n",
- (long)getpid()))
- /* Note: the pclose will probably see
- * the termination of the grandchild
- * in addition to the mail process, since
- * it (the grandchild) is likely to exit
- * after closing its stdout.
- */
- status = cron_pclose(mail);
- }
-
- /* if there was output and we could not mail it,
- * log the facts so the poor user can figure out
- * what's going on.
- */
- if (mailto && status) {
- char buf[MAX_TEMPSTR];
-
- sprintf(buf,
- "mailed %d byte%s of output but got status 0x%04x\n",
- bytes, (bytes==1)?"":"s",
- status);
- log_it(usernm, getpid(), "MAIL", buf);
- }
-
- } /*if data from grandchild*/
-
- Debug(DPROC, ("[%ld] got EOF from grandchild\n",
- (long)getpid()))
-
- fclose(in); /* also closes stdout_pipe[READ_PIPE] */
- }
-
/* wait for children to die.
*/
+ int status;
for (; children > 0; children--) {
+ char msg[256];
WAIT_T waiter;
PID_T pid;
@@ -497,16 +384,127 @@
;
if (pid < OK) {
Debug(DPROC,
- ("[%ld] no more grandchildren--mail written?\n",
+ ("[%ld] no more grandchildren\n",
(long)getpid()))
break;
}
Debug(DPROC, ("[%ld] grandchild #%ld finished, status=%04x",
- (long)getpid(), (long)pid, WEXITSTATUS(waiter)))
- if (WIFSIGNALED(waiter) && WCOREDUMP(waiter))
- Debug(DPROC, (", dumped core"))
- Debug(DPROC, ("\n"))
- }
+ (long)getpid(), (long)pid, waiter))
+
+ if (WIFEXITED(waiter) && WEXITSTATUS(waiter)) {
+ status=waiter;
+ snprintf(msg, 256, "grandchild #%d failed with exit
status %d", pid, WEXITSTATUS(waiter));
+ log_it("CRON",getpid(),"error",msg);
+ } else if (WIFSIGNALED(waiter)) {
+ status=waiter;
+ snprintf(msg, 256, "grandchild #%d terminated by signal
%d%s",
+ pid, WTERMSIG(waiter),
+ WCOREDUMP(waiter)?", dumped core":"");
+ log_it("CRON",getpid(),"error",msg);
+ }
+ }
+
+ // Finally, send any output of the command to the mailer; also, alert
+ // the user if their job failed. Avoid popening the mailcmd until now
+ // since sendmail may time out, and to write info about the exit
+ // status.
+
+ long pos;
+
+ fseek(out, 0, SEEK_END);
+ pos=ftell(out);
+ fseek(out, 0, SEEK_SET);
+
+ Debug(DPROC|DEXT, ("[%d] got %ld bytes data from grandchild tmpfile\n",
+ getpid(), (long)pos))
+ if (pos==0 && status==0) return;
+
+ // get name of recipient.
+ if (mailto==NULL /*|| !*mailto*/) mailto=usernm;
+ else if (!*mailto) mailto=NULL;
+
+ register FILE *mail;
+ register int bytes = 1;
+
+ register char **env;
+ auto char mailcmd[MAX_COMMAND];
+ auto char hostname[MAXHOSTNAMELEN];
+
+ (void) gethostname(hostname, MAXHOSTNAMELEN);
+ (void)sprintf(mailcmd, MAILFMT, MAILARG);
+ // mailcmd, mailto);
+ if (!(mail = cron_popen(mailcmd, "w", e->pwd))) {
+ perror(mailcmd);
+ (void) _exit(ERROR_EXIT);
+ }
+ fprintf(mail, "From: root (Cron Daemon)\n");
+ fprintf(mail, "To: %s\n", mailto);
+ fprintf(mail, "Subject: Cron <[EMAIL PROTECTED]> %s%s\n",
+ usernm, first_word(hostname, "."),
+ e->cmd, status?" (failed)":"");
+ # if defined(MAIL_DATE)
+ fprintf(mail, "Date: %s\n",
+ arpadate(&StartTime));
+ # endif /* MAIL_DATE */
+
+ for (env = e->envp; *env; env++)
+ fprintf(mail, "X-Cron-Env: <%s>\n",
+ *env);
+ fputc('\n', mail);
+
+ if (WIFEXITED(status) && (status=WEXITSTATUS(status))) {
+ fprintf(mail, "command failed with exit status %d\n\n", status);
+ } else if (WIFSIGNALED(status)) {
+ fprintf(mail, "command terminated by signal %d%s\n\n",
+ WTERMSIG(status),
+ WCOREDUMP(status)?", dumped core":"");
+ }
+
+ // Finally, send any output of the command to the mailer; also, alert
+ // the user if their job failed. Avoid popening the mailcmd until now
+ // since sendmail may time out, and to write info about the exit
+ // status.
+
+ for ( ; 1; ) {
+ char buf[1<<12];
+ int ret, remain;
+ if ((ret=fread(buf, 1, sizeof(buf), out))==0) break;
+ for (remain=ret; remain!=0; ) {
+ ret=fwrite(buf, 1, remain, mail);
+ if (ret>0) { remain-=ret; continue; }
+ // XXX error
+ break;
+ }
+ }
+
+ Debug(DPROC, ("[%d] closing pipe to mail\n", getpid()))
+ status = cron_pclose(mail);
+
+ /* if there was output and we could not mail it,
+ * log the facts so the poor user can figure out
+ * what's going on.
+ */
+ if (status) {
+ char buf[MAX_TEMPSTR];
+ snprintf(buf, MAX_TEMPSTR,
+ "mailed %d byte%s of output; "
+ "but got status 0x%04x, "
+ "\n",
+ bytes, (bytes==1)?"":"s", status);
+ log_it(usernm, getpid(), "MAIL", buf);
+ }
+
+ if (ferror(out)) {
+ log_it(usernm, getpid(), "MAIL", "stream error reading output");
+ }
+
+ fclose(out);
+
+ if ((e->flags & DONT_LOG) == 0) {
+ char *x = mkprints((u_char *)e->cmd, strlen(e->cmd));
+ log_it(usernm, getpid(), "END", x);
+ free(x);
+ }
}
static int
Binary files cron-4.1.orig/do_command.o and cron-4.1/do_command.o differ
Binary files cron-4.1.orig/entry.o and cron-4.1/entry.o differ
Binary files cron-4.1.orig/env.o and cron-4.1/env.o differ
Binary files cron-4.1.orig/job.o and cron-4.1/job.o differ
Binary files cron-4.1.orig/misc.o and cron-4.1/misc.o differ
Binary files cron-4.1.orig/popen.o and cron-4.1/popen.o differ
Binary files cron-4.1.orig/pw_dup.o and cron-4.1/pw_dup.o differ
Binary files cron-4.1.orig/.swp and cron-4.1/.swp differ
Binary files cron-4.1.orig/user.o and cron-4.1/user.o differ