Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F143647022
D20046.id62534.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D20046.id62534.diff
View Options
Index: head/usr.sbin/cron/cron/cron.h
===================================================================
--- head/usr.sbin/cron/cron/cron.h
+++ head/usr.sbin/cron/cron/cron.h
@@ -191,6 +191,8 @@
#define NOT_UNTIL 0x10
#define SEC_RES 0x20
#define INTERVAL 0x40
+#define DONT_LOG 0x80
+#define MAIL_WHEN_ERR 0x100
time_t lastrun;
} entry;
@@ -257,7 +259,7 @@
entry *load_entry(FILE *, void (*)(char *),
struct passwd *, char **);
-FILE *cron_popen(char *, char *, entry *);
+FILE *cron_popen(char *, char *, entry *, PID_T *);
/* in the C tradition, we only create
Index: head/usr.sbin/cron/cron/do_command.c
===================================================================
--- head/usr.sbin/cron/cron/do_command.c
+++ head/usr.sbin/cron/cron/do_command.c
@@ -41,6 +41,7 @@
static void child_process(entry *, user *),
do_univ(user *);
+static WAIT_T wait_on_child(PID_T, const char *);
void
do_command(e, u)
@@ -94,7 +95,10 @@
int stdin_pipe[2], stdout_pipe[2];
register char *input_data;
char *usernm, *mailto, *mailfrom;
- int children = 0;
+ PID_T jobpid, stdinjob, mailpid;
+ register FILE *mail;
+ register int bytes = 1;
+ int status = 0;
# if defined(LOGIN_CAP)
struct passwd *pwd;
login_cap_t *lc;
@@ -216,7 +220,7 @@
/* fork again, this time so we can exec the user's command.
*/
- switch (vfork()) {
+ switch (jobpid = vfork()) {
case -1:
log_it("CRON",getpid(),"error","can't vfork");
exit(ERROR_EXIT);
@@ -237,7 +241,7 @@
* the actual user command shell was going to get and the
* PID is part of the log message.
*/
- /*local*/{
+ if ((e->flags & DONT_LOG) == 0) {
char *x = mkprints((u_char *)e->cmd, strlen(e->cmd));
log_it(usernm, getpid(), "CMD", x);
@@ -359,8 +363,6 @@
break;
}
- children++;
-
/* middle process, child of original cron, parent of process running
* the user's command.
*/
@@ -384,7 +386,7 @@
* we would block here. thus we must fork again.
*/
- if (*input_data && fork() == 0) {
+ if (*input_data && (stdinjob = fork()) == 0) {
register FILE *out = fdopen(stdin_pipe[WRITE_PIPE], "w");
register int need_newline = FALSE;
register int escaped = FALSE;
@@ -440,8 +442,6 @@
*/
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
@@ -462,10 +462,6 @@
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))
@@ -500,7 +496,7 @@
hostname[sizeof(hostname) - 1] = '\0';
(void) snprintf(mailcmd, sizeof(mailcmd),
MAILARGS, MAILCMD);
- if (!(mail = cron_popen(mailcmd, "w", e))) {
+ if (!(mail = cron_popen(mailcmd, "w", e, &mailpid))) {
warn("%s", MAILCMD);
(void) _exit(ERROR_EXIT);
}
@@ -538,28 +534,56 @@
if (mailto)
putc(ch, mail);
}
+ }
+ /*if data from grandchild*/
- /* only close pipe if we opened it -- i.e., we're
- * mailing...
- */
+ Debug(DPROC, ("[%d] got EOF from grandchild\n", getpid()))
- 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);
- }
+ /* also closes stdout_pipe[READ_PIPE] */
+ fclose(in);
+ }
+ /* wait for children to die.
+ */
+ if (jobpid > 0) {
+ WAIT_T waiter;
+
+ waiter = wait_on_child(jobpid, "grandchild command job");
+
+ /* 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
+ && mailto) {
+ Debug(DPROC, ("[%d] %s executed successfully, mail suppressed\n",
+ getpid(), "grandchild command job"))
+ kill(mailpid, SIGKILL);
+ (void)fclose(mail);
+ mailto = NULL;
+ }
+
+
+ /* 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) {
+ if (status) {
char buf[MAX_TEMPSTR];
snprintf(buf, sizeof(buf),
@@ -568,35 +592,38 @@
status);
log_it(usernm, getpid(), "MAIL", buf);
}
+ }
+ }
- } /*if data from grandchild*/
+ if (*input_data && stdinjob > 0)
+ wait_on_child(stdinjob, "grandchild stdinjob");
+}
- Debug(DPROC, ("[%d] got EOF from grandchild\n", getpid()))
+static WAIT_T
+wait_on_child(PID_T childpid, const char *name) {
+ WAIT_T waiter;
+ PID_T pid;
- fclose(in); /* also closes stdout_pipe[READ_PIPE] */
- }
+ Debug(DPROC, ("[%d] waiting for %s (%d) to finish\n",
+ getpid(), name, childpid))
- /* wait for children to die.
- */
- for (; children > 0; children--)
- {
- WAIT_T waiter;
- PID_T pid;
+#ifdef POSIX
+ while ((pid = waitpid(childpid, &waiter, 0)) < 0 && errno == EINTR)
+#else
+ while ((pid = wait4(childpid, &waiter, 0, NULL)) < 0 && errno == EINTR)
+#endif
+ ;
- Debug(DPROC, ("[%d] waiting for grandchild #%d to finish\n",
- getpid(), children))
- pid = wait(&waiter);
- if (pid < OK) {
- Debug(DPROC, ("[%d] no more grandchildren--mail written?\n",
- getpid()))
- 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"))
- }
+ if (pid < OK)
+ return waiter;
+
+ Debug(DPROC, ("[%d] %s (%d) finished, status=%04x",
+ getpid(), name, pid, WEXITSTATUS(waiter)))
+ if (WIFSIGNALED(waiter) && WCOREDUMP(waiter))
+ Debug(DPROC, (", dumped core"))
+ Debug(DPROC, ("\n"))
+
+ return waiter;
}
Index: head/usr.sbin/cron/cron/popen.c
===================================================================
--- head/usr.sbin/cron/cron/popen.c
+++ head/usr.sbin/cron/cron/popen.c
@@ -55,9 +55,10 @@
static int fds;
FILE *
-cron_popen(program, type, e)
+cron_popen(program, type, e, pidptr)
char *program, *type;
entry *e;
+ PID_T *pidptr;
{
register char *cp;
FILE *iop;
@@ -218,6 +219,9 @@
free((char *)argv[argc]);
}
#endif
+
+ *pidptr = pid;
+
return(iop);
}
Index: head/usr.sbin/cron/crontab/crontab.5
===================================================================
--- head/usr.sbin/cron/crontab/crontab.5
+++ head/usr.sbin/cron/crontab/crontab.5
@@ -17,7 +17,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 19, 2019
+.Dd September 24, 2019
.Dt CRONTAB 5
.Os
.Sh NAME
@@ -199,6 +199,8 @@
.Pp
The ``sixth'' field (the rest of the line) specifies the command to be
run.
+One or more command options may precede the command to modify processing
+behavior.
The entire command portion of the line, up to a newline or %
character, will be executed by
.Pa /bin/sh
@@ -211,6 +213,22 @@
after the first % will be sent to the command as standard
input.
.Pp
+The following command options can be supplied:
+.Bl -tag -width Ds
+.It Fl n
+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
+Execution will not be logged.
+.El
+.sp
+Duplicate options are not allowed.
+.Pp
Note: The day of a command's execution can be specified by two
fields \(em day of month, and day of week.
If both fields are
@@ -271,6 +289,10 @@
5 4 * * sun echo "run at 5 after 4 every sunday"
# run at 5 minutes intervals, no matter how long it takes
@300 svnlite up /usr/src
+# run every minute, suppress logging
+* * * * * -q date
+# run every minute, only send mail if ping fails
+* * * * * -n ping -c 1 freebsd.org
.Ed
.Sh SEE ALSO
.Xr crontab 1 ,
@@ -314,6 +336,14 @@
.Sq @
directives that can appear in place of the first five fields
are extensions.
+.Pp
+Command processing can be modified using command options.
+The
+.Sq -q
+option suppresses logging.
+The
+.Sq -n
+option does not mail on successful run.
.Sh AUTHORS
.An Paul Vixie Aq Mt paul@vix.com
.Sh BUGS
Index: head/usr.sbin/cron/lib/entry.c
===================================================================
--- head/usr.sbin/cron/lib/entry.c
+++ head/usr.sbin/cron/lib/entry.c
@@ -35,7 +35,8 @@
typedef enum ecode {
e_none, e_minute, e_hour, e_dom, e_month, e_dow,
- e_cmd, e_timespec, e_username, e_group, e_mem
+ e_cmd, e_timespec, e_username, e_group, e_option,
+ e_mem
#ifdef LOGIN_CAP
, e_class
#endif
@@ -58,6 +59,7 @@
"bad time specifier",
"bad username",
"bad group name",
+ "bad option",
"out of memory",
#ifdef LOGIN_CAP
"bad class name",
@@ -428,6 +430,53 @@
goto eof;
}
#endif
+
+ Debug(DPARS, ("load_entry()...checking for command options\n"))
+
+ ch = get_char(file);
+
+ while (ch == '-') {
+ Debug(DPARS|DEXT, ("load_entry()...expecting option\n"))
+ switch (ch = get_char(file)) {
+ case 'n':
+ Debug(DPARS|DEXT, ("load_entry()...got MAIL_WHEN_ERR ('n') option\n"))
+ /* only allow the user to set the option once */
+ if ((e->flags & MAIL_WHEN_ERR) == MAIL_WHEN_ERR) {
+ Debug(DPARS|DEXT, ("load_entry()...duplicate MAIL_WHEN_ERR ('n') option\n"))
+ ecode = e_option;
+ goto eof;
+ }
+ e->flags |= MAIL_WHEN_ERR;
+ break;
+ case 'q':
+ Debug(DPARS|DEXT, ("load_entry()...got DONT_LOG ('q') option\n"))
+ /* only allow the user to set the option once */
+ if ((e->flags & DONT_LOG) == DONT_LOG) {
+ Debug(DPARS|DEXT, ("load_entry()...duplicate DONT_LOG ('q') option\n"))
+ ecode = e_option;
+ goto eof;
+ }
+ e->flags |= DONT_LOG;
+ break;
+ default:
+ Debug(DPARS|DEXT, ("load_entry()...invalid option '%c'\n", ch))
+ 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;
+ goto eof;
+ }
+ }
+
+ unget_char(ch, file);
Debug(DPARS, ("load_entry()...about to parse command\n"))
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Feb 1, 4:09 AM (14 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28269701
Default Alt Text
D20046.id62534.diff (10 KB)
Attached To
Mode
D20046: cron: add log suppression and mail suppression for successful runs
Attached
Detach File
Event Timeline
Log In to Comment