diff options
author | job <job@cvs.openbsd.org> | 2018-06-13 11:27:31 +0000 |
---|---|---|
committer | job <job@cvs.openbsd.org> | 2018-06-13 11:27:31 +0000 |
commit | ffebb6c34c09a29f5b265d36ca12f1d79278c089 (patch) | |
tree | efc7fb01609ac59ecd75e1b03e22bc64eec44824 /usr.sbin | |
parent | 442a17b8b75aa93a5dbb58b2d44f69df11dbfc3c (diff) |
Add crontab entry option -n for "No mail when run successful"
OK jmc@ millert@
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/cron/crontab.5 | 29 | ||||
-rw-r--r-- | usr.sbin/cron/do_command.c | 101 | ||||
-rw-r--r-- | usr.sbin/cron/entry.c | 22 | ||||
-rw-r--r-- | usr.sbin/cron/structs.h | 3 |
4 files changed, 95 insertions, 60 deletions
diff --git a/usr.sbin/cron/crontab.5 b/usr.sbin/cron/crontab.5 index 9c2e651980a..cdda7bb40dd 100644 --- a/usr.sbin/cron/crontab.5 +++ b/usr.sbin/cron/crontab.5 @@ -17,9 +17,9 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.\" $OpenBSD: crontab.5,v 1.34 2016/10/12 17:27:08 schwarze Exp $ +.\" $OpenBSD: crontab.5,v 1.35 2018/06/13 11:27:30 job Exp $ .\" -.Dd $Mdocdate: October 12 2016 $ +.Dd $Mdocdate: June 13 2018 $ .Dt CRONTAB 5 .Os .Sh NAME @@ -193,14 +193,20 @@ will be changed into newline characters, and all data after the first .Ql % will be sent to the command as standard input. -If the -.Ar command -field begins with -.Ql -q , -execution will not be logged. -Use whitespace to separate -.Ql -q -from the command. +.Pp +Commands may be modified as follows: +.Bl -tag -width Ds +.It Fl n Ar command +No mail is sent after a successful run. +The execution output will only be mailed if the command exits with a non-zero +exit code. +The +.Fl -n +option is an attempt to cure potentially copious volumes of mail coming from +.Xr cron 8 . +.It Fl q Ar command +Execution will not be logged. +.El .Pp Commands are executed by .Xr cron 8 @@ -329,6 +335,9 @@ Ranges may include .It Months or days of the week can be specified by name. .It +Mailing after a successful run can be suppressed with +.Fl n . +.It Logging can be suppressed with .Ql -q . .It diff --git a/usr.sbin/cron/do_command.c b/usr.sbin/cron/do_command.c index 6a4022fcc9a..0e711b636bb 100644 --- a/usr.sbin/cron/do_command.c +++ b/usr.sbin/cron/do_command.c @@ -1,8 +1,9 @@ -/* $OpenBSD: do_command.c,v 1.57 2017/10/23 08:39:26 friehm Exp $ */ +/* $OpenBSD: do_command.c,v 1.58 2018/06/13 11:27:30 job Exp $ */ /* Copyright 1988,1990,1993,1994 by Paul Vixie * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1997,2000 by Internet Software Consortium, Inc. + * Copyright (c) 2018 Job Snijders <job@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -80,7 +81,6 @@ child_process(entry *e, user *u) char **p, *input_data, *usernm; auth_session_t *as; login_cap_t *lc; - int children = 0; extern char **environ; /* mark ourselves as different to PS command watchers */ @@ -146,7 +146,9 @@ child_process(entry *e, user *u) /* fork again, this time so we can exec the user's command. */ - switch (fork()) { + + pid_t jobpid; + switch (jobpid = fork()) { case -1: syslog(LOG_ERR, "(CRON) CAN'T FORK (%m)"); _exit(EXIT_FAILURE); @@ -260,8 +262,6 @@ child_process(entry *e, user *u) break; } - children++; - /* middle process, child of original cron, parent of process running * the user's command. */ @@ -283,7 +283,8 @@ child_process(entry *e, user *u) * we would block here. thus we must fork again. */ - if (*input_data && fork() == 0) { + pid_t stdinjob; + if (*input_data && (stdinjob = fork()) == 0) { FILE *out = fdopen(stdin_pipe[WRITE_PIPE], "w"); int need_newline = FALSE; int escaped = FALSE; @@ -331,8 +332,6 @@ child_process(entry *e, user *u) */ close(stdin_pipe[WRITE_PIPE]); - children++; - /* * read output from the grandchild. it's stderr has been redirected to * it's stdout, which has been redirected to our pipe. if there is any @@ -342,15 +341,17 @@ child_process(entry *e, user *u) (void) signal(SIGPIPE, SIG_IGN); in = fdopen(stdout_pipe[READ_PIPE], "r"); + + char *mailto; + FILE *mail = NULL; + int status = 0; + pid_t mailpid; + size_t bytes = 1; + if (in != NULL) { int ch = getc(in); if (ch != EOF) { - FILE *mail = NULL; - char *mailto; - size_t bytes = 1; - int status = 0; - pid_t mailpid; /* get name of recipient. this is MAILTO if set to a * valid local username; USER otherwise. @@ -415,30 +416,6 @@ child_process(entry *e, user *u) fputc(ch, mail); } - /* only close pipe if we opened it -- i.e., we're - * mailing... - */ - - if (mail) { - /* 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, mailpid); - } - - /* 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 (mail && status) { - syslog(LOG_NOTICE, "(%s) MAIL (mailed %zu byte" - "%s of output but got status 0x%04x)", usernm, - bytes, (bytes == 1) ? "" : "s", status); - } - } /*if data from grandchild*/ fclose(in); /* also closes stdout_pipe[READ_PIPE] */ @@ -446,20 +423,50 @@ child_process(entry *e, user *u) /* wait for children to die. */ - for (; children > 0; children--) { - int waiter; - pid_t pid; - - while ((pid = wait(&waiter)) < 0 && errno == EINTR) + int waiter; + if (jobpid > 0) { + ; + while (waitpid(jobpid, &waiter, 0) < 0 && errno == EINTR) ; - if (pid < 0) { - break; + + /* If everything went well, and -n was set, _and_ we have mail, + * we won't be mailing... so shoot the messenger! + */ + if (WIFEXITED(waiter) && WEXITSTATUS(waiter) == 0 + && (e->flags & MAIL_WHEN_ERR) == MAIL_WHEN_ERR + && mail) { + kill(mailpid, SIGKILL); + (void)fclose(mail); + mail = NULL; } - /* - if (WIFSIGNALED(waiter) && WCOREDUMP(waiter)) - Debug(DPROC, (", dumped core")) + + /* only close pipe if we opened it -- i.e., we're + * mailing... */ + if (mail) { + /* + * 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, mailpid); + } + + /* 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 (mail && status) { + syslog(LOG_NOTICE, "(%s) MAIL (mailed %zu byte" + "%s of output but got status 0x%04x)", usernm, + bytes, (bytes == 1) ? "" : "s", status); + } } + + if (stdinjob > 0) + while (waitpid(stdinjob, &waiter, 0) < 0 && errno == EINTR) + ; } int diff --git a/usr.sbin/cron/entry.c b/usr.sbin/cron/entry.c index 761f01d3d6f..bb0221bffb6 100644 --- a/usr.sbin/cron/entry.c +++ b/usr.sbin/cron/entry.c @@ -1,4 +1,4 @@ -/* $OpenBSD: entry.c,v 1.48 2015/11/14 13:09:14 millert Exp $ */ +/* $OpenBSD: entry.c,v 1.49 2018/06/13 11:27:30 job Exp $ */ /* * Copyright 1988,1990,1993,1994 by Paul Vixie @@ -338,14 +338,32 @@ load_entry(FILE *file, void (*error_func)(const char *), struct passwd *pw, ch = get_char(file); while (ch == '-') { switch (ch = get_char(file)) { + case 'n': + /* only allow the user to set the option once */ + if ((e->flags & MAIL_WHEN_ERR) == MAIL_WHEN_ERR) { + ecode = e_option; + goto eof; + } + e->flags |= MAIL_WHEN_ERR; + break; case 'q': + /* only allow the user to set the option once */ + if ((e->flags & DONT_LOG) == DONT_LOG) { + ecode = e_option; + goto eof; + } e->flags |= DONT_LOG; - Skip_Nonblanks(ch, file) break; default: ecode = e_option; goto eof; } + ch = get_char(file); + if (ch!='\t' && ch!=' ') { + ecode = e_option; + goto eof; + } + Skip_Blanks(ch, file) if (ch == EOF || ch == '\n') { ecode = e_cmd; diff --git a/usr.sbin/cron/structs.h b/usr.sbin/cron/structs.h index af0d75c3b55..c380b14f90d 100644 --- a/usr.sbin/cron/structs.h +++ b/usr.sbin/cron/structs.h @@ -1,4 +1,4 @@ -/* $OpenBSD: structs.h,v 1.8 2016/01/11 14:23:50 millert Exp $ */ +/* $OpenBSD: structs.h,v 1.9 2018/06/13 11:27:30 job Exp $ */ /* * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") @@ -38,6 +38,7 @@ typedef struct _entry { #define DOW_STAR 0x08 #define WHEN_REBOOT 0x10 #define DONT_LOG 0x20 +#define MAIL_WHEN_ERR 0x40 } entry; /* the crontab database will be a list of the |