1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
|
From: Christian Kastner <ckk@kvr.at>
Date: Fri, 15 Jan 2016 23:05:10 +0100
Subject: Selective logging
This implements a fine-grained control over what the cron daemon logs when it
executes jobs. This is driven via the '-L' command line option, which accepts a
bitmask of values for logging the start, end, failure and PID of jobs. The
following things can be logged:
* Start of cron jobs
* End of cron jobs
* Failed jobs
* Include PID of cron job in messages
The default is to log the start of jobs.
Initially contributed by Steve Fosdick <dbugs@pelvoux.nildram.co.uk>.
Bug-Debian: https://bugs.debian.org/271747
Bug-Debian: https://bugs.debian.org/318247
Forwarded: no
Last-Update: 2016-01-15
---
cron.8 | 25 ++++++++++++++++++++++++-
cron.c | 8 ++++++--
cron.h | 9 ++++++++-
do_command.c | 56 ++++++++++++++++++++++++++++++++++++++++----------------
4 files changed, 78 insertions(+), 20 deletions(-)
diff --git a/cron.8 b/cron.8
index 23a50c0..77cb100 100644
--- a/cron.8
+++ b/cron.8
@@ -25,6 +25,8 @@ cron \- daemon to execute scheduled commands (Vixie Cron)
cron
.RB [ \-f ]
.RB [ \-l ]
+.RB [ \-L
+.IR loglevel ]
.SH DESCRIPTION
.I cron
is started automatically from /etc/init.d on entering multi-user
@@ -38,6 +40,27 @@ Stay in foreground mode, don't daemonize.
Enable LSB compliant names for /etc/cron.d files. This setting, however, does
not affect the parsing of files under /etc/cron.hourly, /etc/cron.daily,
/etc/cron.weekly or /etc/cron.monthly.
+.TP
+.B \-L loglevel
+Tell cron what to log about \fBjobs\fR (errors are logged regardless of this
+value) as the sum of the following values:
+.br
+.RS 12
+.IP \fB1\fR
+will log the start of all cron jobs
+.IP \fB2\fR
+will log the end of all cron jobs
+.IP \fB4\fR
+will log all failed jobs (exit status != 0)
+.IP \fB8\fR
+will log the process number of all cron jobs
+.RE
+.IP
+The default is to log the start of all jobs (1).
+Logging will be disabled if
+.I levels
+is set to zero (0).
+A value of fifteen (15) will select all options.
.SH NOTES
.PP
.I cron
@@ -272,7 +295,7 @@ daemon. This file determines whether
will read the system's environment variables and makes it possible to add
additional options to the
.I cron
-program before it is executed, for example to define how
+program before it is executed, either to configure its logging or to define how
it will treat the files under /etc/cron.d.
.SH "SEE ALSO"
diff --git a/cron.c b/cron.c
index 53a6dae..84b19e6 100644
--- a/cron.c
+++ b/cron.c
@@ -447,9 +447,9 @@ sighup_handler(int x) {
#if DEBUGGING
-const char *getoptarg = "flx:";
+const char *getoptarg = "flL:x:";
#else
-const char *getoptarg = "fl";
+const char *getoptarg = "flL:";
#endif
static void
@@ -461,6 +461,7 @@ parse_args(argc, argv)
stay_foreground = 0;
lsbsysinit_mode = 0;
+ log_level = 1;
while (EOF != (argch = getopt(argc, argv, getoptarg))) {
switch (argch) {
@@ -472,6 +473,9 @@ parse_args(argc, argv)
case 'l':
lsbsysinit_mode = 1;
break;
+ case 'L':
+ log_level = atoi(optarg);
+ break;
#if DEBUGGING
case 'x':
if (!set_debug_flags(optarg))
diff --git a/cron.h b/cron.h
index 30b36e9..6c866a4 100644
--- a/cron.h
+++ b/cron.h
@@ -138,6 +138,12 @@
typedef int time_min;
+/* Log levels */
+#define CRON_LOG_JOBSTART 0x01
+#define CRON_LOG_JOBEND 0x02
+#define CRON_LOG_JOBFAILED 0x04
+#define CRON_LOG_JOBPID 0x08
+
#define SECONDS_PER_MINUTE 60
#define FIRST_MINUTE 0
@@ -210,7 +216,6 @@ typedef struct _cron_db {
time_t sysd_mtime; /* last modtime on system crondir */
} cron_db;
-
void set_cron_uid __P((void)),
set_cron_cwd __P((void)),
load_database __P((cron_db *)),
@@ -294,6 +299,7 @@ static long GMToff;
int stay_foreground;
int lsbsysinit_mode;
+int log_level;
char cron_default_mail_charset[MAX_ENVSTR] = "";
@@ -310,6 +316,7 @@ extern char *copyright[],
*DowNames[],
*ProgramName;
extern int lsbsysinit_mode;
+extern int log_level;
extern int LineNumber;
extern time_t StartTime;
extern time_min timeRunning;
diff --git a/do_command.c b/do_command.c
index 923e507..e024995 100644
--- a/do_command.c
+++ b/do_command.c
@@ -131,6 +131,7 @@ child_process(e, u)
register char *input_data;
char *usernm, *mailto;
int children = 0;
+ pid_t job_pid;
#if defined(USE_PAM)
int retcode = 0;
#endif
@@ -228,7 +229,7 @@ child_process(e, u)
/* fork again, this time so we can exec the user's command.
*/
- switch (fork()) {
+ switch (job_pid = fork()) {
case -1:
log_it("CRON",getpid(),"error","can't fork");
exit(ERROR_EXIT);
@@ -242,14 +243,12 @@ child_process(e, u)
* the actual user command shell was going to get and the
* PID is part of the log message.
*/
- /*local*/{
+ if ((log_level & CRON_LOG_JOBSTART) && ! (log_level & CRON_LOG_JOBPID)) {
char *x = mkprints((u_char *)e->cmd, strlen(e->cmd));
-
log_it(usernm, getpid(), "CMD", x);
free(x);
}
-
- /* that's the last thing we'll log. close the log files.
+ /* nothing to log from now on. close the log files.
*/
log_close();
@@ -357,6 +356,16 @@ child_process(e, u)
break;
default:
/* parent process */
+ /* write a log message if we want the parent and child
+ * PID values
+ */
+ if ( (log_level & CRON_LOG_JOBSTART) && (log_level & CRON_LOG_JOBPID)) {
+ char logcmd[MAX_COMMAND + 8];
+ snprintf(logcmd, sizeof(logcmd), "[%d] %s", (int) job_pid, e->cmd);
+ char *x = mkprints((u_char *)logcmd, strlen(logcmd));
+ log_it(usernm, getpid(), "CMD", x);
+ free(x);
+ }
break;
}
@@ -458,17 +467,19 @@ child_process(e, u)
Debug(DPROC, ("[%d] grandchild #%d finished, status=%04x\n",
getpid(), pid, WEXITSTATUS(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);
+ if (log_level & CRON_LOG_JOBFAILED) {
+ 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);
+ }
}
}
@@ -616,6 +627,19 @@ child_process(e, u)
mail_finished:
fclose(tmpout);
+ if (log_level & CRON_LOG_JOBEND) {
+ char *x;
+ if (log_level & CRON_LOG_JOBPID) {
+ char logcmd[MAX_COMMAND + 8];
+ snprintf(logcmd, sizeof(logcmd), "[%d] %s", (int) job_pid, e->cmd);
+ x = mkprints((u_char *)logcmd, strlen(logcmd));
+ } else {
+ x = mkprints((u_char *)e->cmd, strlen(e->cmd));
+ }
+ log_it(usernm, job_pid, "END", x);
+ free(x);
+ }
+
#if defined(USE_PAM)
pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT);
retcode = pam_close_session(pamh, PAM_SILENT);
|