Subject: bin/36539: a mass of fixes for cron(8)
To: None <gnats-admin@netbsd.org, netbsd-bugs@netbsd.org>
From: Greg A. Woods <woods@planix.com>
List: netbsd-bugs
Date: 06/23/2007 20:35:00
>Number:         36539
>Category:       bin
>Synopsis:       a mass of fixes for cron(8)
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Jun 23 20:35:00 +0000 2007
>Originator:     Greg A. Woods
>Release:        netbsd-4 2007/06/22
>Organization:
Planix, Inc.; Toronto, Ontario; Canada
>Environment:
	
	
System: NetBSD
>Description:

	the changes here should be mostly self-explanitory

>How-To-Repeat:

	be appalled at the state of the cron code and docs and it's poor
	logging ability, etc.

>Fix:

cvs diff: Diffing usr.sbin/cron
Index: usr.sbin/cron/Makefile
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.sbin/cron/Makefile,v
retrieving revision 1.12
diff -u -r1.12 Makefile
--- usr.sbin/cron/Makefile	11 May 2006 23:16:30 -0000	1.12
+++ usr.sbin/cron/Makefile	28 May 2007 20:22:48 -0000
@@ -4,8 +4,9 @@
 SRCS=	cron.c database.c do_command.c entry.c env.c job.c \
 	misc.c popen.c user.c
 CPPFLAGS+=-I${.CURDIR} -DLOGIN_CAP
+CPPFLAGS+=-DDEBUGGING
 LDADD+=-lutil
-MAN=	cron.8
+MAN=	cron.8 crontab.5 crontab.1
 
 WARNS=  3
 
Index: usr.sbin/cron/README.woods
===================================================================
RCS file: usr.sbin/cron/README.woods
diff -N usr.sbin/cron/README.woods
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr.sbin/cron/README.woods	28 May 2007 20:22:18 -0000
@@ -0,0 +1,7 @@
+Keep cron up-to-date
+
+	cd /usr/src-current/usr.sbin/cron
+	cvs -q update
+
+	find . -type f ! -name '.#*' -print -o -name CVS -prune | pax -rw /usr/src/usr.sbin/cron
+	find . -type f ! -name '.#*' -print -o -name CVS -prune | pax -rw /usr/src-4/usr.sbin/cron
Index: usr.sbin/cron/config.h
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.sbin/cron/config.h,v
retrieving revision 1.6
diff -u -r1.6 config.h
--- usr.sbin/cron/config.h	9 Apr 1999 02:47:03 -0000	1.6
+++ usr.sbin/cron/config.h	28 May 2007 20:22:49 -0000
@@ -44,11 +44,10 @@
 			 */
 
 #define MAILCMD _PATH_SENDMAIL					/*-*/
-#define MAILARGS "%s -FCronDaemon -odi -oem -oi -or0s -t"	/*-*/
+#define MAILARGS "%s -FCronDaemon -odi -oem -oi -t"		/*-*/
 			/* -Fx	 = set full-name of sender
 			 * -odi	 = Option Deliverymode Interactive
 			 * -oem	 = Option Errors Mailedtosender
-			 * -or0s = Option Readtimeout -- don't time out
 			 * -t    = read recipient from header of message
 			 */
 
Index: usr.sbin/cron/cron.8
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.sbin/cron/cron.8,v
retrieving revision 1.7
diff -u -r1.7 cron.8
--- usr.sbin/cron/cron.8	20 Mar 2004 18:54:33 -0000	1.7
+++ usr.sbin/cron/cron.8	28 May 2007 20:22:49 -0000
@@ -27,12 +27,15 @@
 .Nd daemon to execute scheduled commands (Vixie Cron)
 .Sh SYNOPSIS
 .Nm
+.Op Fl f Ar system-crontab
 .Op Fl x Ar debugflags
 .Sh DESCRIPTION
 .Nm
-is normally started during system boot by
+is normally started during system boot by the
 .Xr rc.d 8
-framework, if cron is switched on in
+framework, if
+.Dv cron
+is switched on in
 .Xr rc.conf 5 .
 .Pp
 .Nm
@@ -40,11 +43,12 @@
 .Pa /var/cron/tabs
 for crontab files which are named after accounts in
 .Pa /etc/passwd .
-Crontabs found are loaded into memory.
+All crontab files which are found are loaded into memory.
 .Nm
-also searches for
-.Pa /etc/crontab
-which is in a different format (see
+also searches for the system crontab, normally named
+.Pa /etc/crontab ,
+which has in a slightly different format with a username field before
+the command (see
 .Xr crontab 5 ) .
 .Nm
 then wakes up every minute, examining all stored crontabs, checking each
@@ -56,20 +60,24 @@
 .Pp
 Additionally,
 .Nm
-checks each minute to see if its spool directory's modtime (or the modtime
-on
+checks each minute to see if its spool directory's last-modified time
+(and the last modified time on the system crontab file,
 .Pa /etc/crontab )
-has changed, and if it has,
+has changed, and if so,
 .Nm
-will then examine the modtime on all crontabs and reload those which have
-changed.
+will then examine the last-modified time on all crontabs and reload all
+those which have changed.
 Thus
 .Nm
 need not be restarted whenever a crontab file is modified.
 Note that the
 .Xr crontab 1
-command updates the modtime of the spool directory whenever it changes a
-crontab.
+command updates the last-modified time of the spool directory whenever
+it changes a crontab file.
+.Pp
+The parameter to the
+.Fl f
+flag changes the default system crontab filename.
 .Pp
 The
 .Fl x
@@ -80,7 +88,9 @@
 .Nm
 writes some additional debugging information to system log during
 its work.
+.Pp
 Available debugging flags are:
+.Pp
 .Bl -tag -width proc -compact
 .It Ar sch
 scheduling
@@ -103,9 +113,9 @@
 .Bl -tag -width /var/cron/tabs -compact
 .It Pa /var/cron/tabs
 .Nm
-spool directory
+spool directory for per-user crontab files
 .It Pa /etc/crontab
-system crontab
+default system crontab filename
 .El
 .Sh SEE ALSO
 .Xr crontab 1 ,
Index: usr.sbin/cron/cron.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.sbin/cron/cron.c,v
retrieving revision 1.13
diff -u -r1.13 cron.c
--- usr.sbin/cron/cron.c	18 Dec 2006 20:11:10 -0000	1.13
+++ usr.sbin/cron/cron.c	28 May 2007 20:22:49 -0000
@@ -27,7 +27,7 @@
 #endif
 
 
-#define	MAIN_PROGRAM
+#define	MAIN_PROGRAM	"[CRON]"
 
 
 #include "cron.h"
@@ -37,6 +37,9 @@
 #else
 # include <time.h>
 #endif
+#if defined(SYSLOG)
+# include <syslog.h>
+#endif
 
 
 static	void	usage(void),
@@ -48,11 +51,25 @@
 		sigchld_handler(int),
 #endif
 		sighup_handler(int),
+		shutdown_handler __P((int)),
 		parse_args(int c, char *v[]);
 
+static int	set_syscron_name __P((const char *));
 
 static void
 usage(void) {
+#if DEBUGGING
+	int df;
+	fprintf(stderr, "usage:  %s [-x debugflag[,...]] [-f system_crontab]\n- debugflags are:  ", getprogname());
+	for (df = 0; DebugFlagNames[df]; df++) {
+		if (df)
+			fputs(", ", stderr);
+		fprintf(stderr, "%s", DebugFlagNames[df]);
+	}
+	fputs("\n", stderr);
+#else
+	fprintf(stderr, "usage:  %s [-f system_crontab]\n", getprogname());
+#endif
 	fprintf(stderr, "usage:  %s [-x debugflag[,...]]\n", getprogname());
 	exit(ERROR_EXIT);
 }
@@ -78,6 +95,8 @@
 	(void) signal(SIGCLD, SIG_IGN);
 #endif
 	(void) signal(SIGHUP, sighup_handler);
+	(void) signal(SIGINT, shutdown_handler);
+	(void) signal(SIGTERM, shutdown_handler);
 
 	acquire_daemonlock(0);
 	set_cron_uid();
@@ -97,12 +116,14 @@
 		(void) fprintf(stderr, "[%d] cron started\n", getpid());
 	} else {
 		if (daemon(1, 0)) {
-			log_it("CRON",getpid(),"DEATH","can't fork");
+			log_it(LOG_ERR, "CRON", getpid(), "DEATH", "can't daemonize");
 			exit(1);
 		}
 	}
-
+	/* re-acquire the pidfile after daemon() */
 	acquire_daemonlock(0);
+	log_it(LOG_DEBUG, "CRON", getpid(), "START", "initial startup");
+
 	database.head = NULL;
 	database.tail = NULL;
 	database.mtime = (time_t) 0;
@@ -233,6 +254,19 @@
 cron_sleep(void) {
 	int	seconds_to_wait;
 
+	/* From FreeBSD PR#5572 by Matt Dillon <dillon@best.net>:
+	 * Look for time step and don't run all the friggin cron jobs in
+	 * between if a major backwards step occurs.  Otherwise, a major 
+	 * time step (e.g. if the time gets messed up on the machine) may 
+	 * cause thousands of cron jobs to be run, especially if you have a lot
+	 * of users.
+	 */
+     
+	seconds_to_wait = (int) (TargetTime - time((time_t*)0));
+     
+	if (seconds_to_wait < -600 || seconds_to_wait > 600) {
+		cron_sync();
+	}
 	do {
 		seconds_to_wait = (int) (TargetTime - time((time_t*)0));
 		Debug(DSCH, ("[%d] TargetTime=%ld, sec-to-wait=%d\n",
@@ -292,23 +326,58 @@
 static void
 sighup_handler(int x __unused)
 {
+	log_it(LOG_INFO, "CRON", getpid(), "LOGROTATE", "received SIGHUP, close and re-open log");
 	log_close();
 }
 
 
 static void
+shutdown_handler(int x)
+{
+	log_it(LOG_INFO, "CRON", getpid(), "SHUTDOWN", "received shutdown signal");
+	log_close();
+
+	exit(0);
+}
+
+
+static int
+set_syscron_name(const char *newname)
+{
+	static int was_set = 0;
+
+	if (was_set)
+		return 0;
+	was_set = 1;
+	syscron_name = newname;
+	return was_set;
+}
+
+static void
 parse_args(int argc, char **argv)
 {
 	int	argch;
 
-	while (-1 != (argch = getopt(argc, argv, "x:"))) {
+#if DEBUGGING
+# define GETOPT_OPTIONS		"f:x:"
+#else
+# define GETOPT_OPTIONS		"f:"
+#endif
+
+	while (-1 != (argch = getopt(argc, argv, GETOPT_OPTIONS))) {
 		switch (argch) {
 		default:
 			usage();
+		case 'f':
+			if (!set_syscron_name((const char *) optarg))
+				usage();
+			break;
+#if DEBUGGING
 		case 'x':
 			if (!set_debug_flags(optarg))
 				usage();
 			break;
 		}
+#endif
 	}
 }
Index: usr.sbin/cron/cron.h
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.sbin/cron/cron.h,v
retrieving revision 1.4
diff -u -r1.4 cron.h
--- usr.sbin/cron/cron.h	16 Mar 2005 02:53:55 -0000	1.4
+++ usr.sbin/cron/cron.h	28 May 2007 20:22:49 -0000
@@ -119,6 +119,9 @@
 #define	Set_LineNum(ln)	{Debug(DPARS|DEXT,("linenum=%d\n",ln)); \
 			 LineNumber = ln; \
 			}
+#define	Set_FileName(fn) {Debug(DPARS|DEXT,("filename=%s\n",fn?fn:"<NONE>")); \
+			 FileName = fn; \
+			}
 
 #define	FIRST_MINUTE	0
 #define	LAST_MINUTE	59
@@ -199,7 +202,7 @@
 		free_entry(entry *),
 		acquire_daemonlock(int),
 		skip_comments(FILE *),
-		log_it(const char *, int, const char *, const char *),
+		log_it(int, const char *, int, const char *, const char *),
 		log_close(void);
 
 int		job_runqueue(void),
@@ -254,7 +257,10 @@
 		NULL
 	};
 
-char	*ProgramName;
+const char	*syscron_name = SYSCRONTAB;
+
+char	*FileName = NULL;
+
 int	LineNumber;
 time_t	TargetTime;
 
@@ -269,7 +275,9 @@
 extern	char	*copyright[],
 		*MonthNames[],
 		*DowNames[],
-		*ProgramName;
+		*ProgramName,
+		*syscron_name;
+extern	char	*FileName;
 extern	int	LineNumber;
 extern	time_t	TargetTime;
 # if DEBUGGING
Index: usr.sbin/cron/crontab.1
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.sbin/cron/crontab.1,v
retrieving revision 1.7
diff -u -r1.7 crontab.1
--- usr.sbin/cron/crontab.1	8 Feb 2002 01:38:47 -0000	1.7
+++ usr.sbin/cron/crontab.1	28 May 2007 20:22:49 -0000
@@ -1,3 +1,4 @@
+.\" -*-nroff-*-
 .\"	$NetBSD: crontab.1,v 1.7 2002/02/08 01:38:47 ross Exp $
 .\"
 .\"/* Copyright 1988,1990,1993 by Paul Vixie
@@ -60,7 +61,7 @@
 option is given, it specifies the name of the user whose crontab is to be
 tweaked.  If this option is not given,
 .I crontab
-examines "your" crontab, i.e., the crontab of the person executing the
+examines ``your'' crontab, i.e., the crontab of the person executing the
 command.  Note that
 .IR su (1)
 can confuse
Index: usr.sbin/cron/crontab.5
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.sbin/cron/crontab.5,v
retrieving revision 1.11
diff -u -r1.11 crontab.5
--- usr.sbin/cron/crontab.5	2 Sep 2004 11:41:27 -0000	1.11
+++ usr.sbin/cron/crontab.5	28 May 2007 20:22:49 -0000
@@ -1,3 +1,4 @@
+.\" -*-nroff-*-
 .\"	$NetBSD: crontab.5,v 1.11 2004/09/02 11:41:27 jmmv Exp $
 .\"
 .\"/* Copyright 1988,1990,1993,1994 by Paul Vixie
@@ -19,7 +20,7 @@
 .\"
 .\" Id: crontab.5,v 2.4 1994/01/15 20:43:43 vixie Exp
 .\"
-.TH CRONTAB 5 "24 January 1994"
+.TH CRONTAB 5 "16 May 2003"
 .UC 4
 .SH NAME
 crontab \- tables for driving cron
@@ -28,12 +29,12 @@
 .I crontab
 file contains instructions to the
 .IR cron (8)
-daemon of the general form: ``run this command at this time on this date''.
+daemon of the general form:  ``run this command at this time on this date''.
 Each user has their own crontab, and commands in any given crontab will be
 executed as the user who owns the crontab.  Uucp and News will usually have
 their own crontabs, eliminating the need for explicitly running
 .IR su (1)
-as part of a cron command.
+as part of a cron command on non-BSD systems.
 .PP
 Blank lines and leading spaces and tabs are ignored.  Lines whose first
 non-space character is a pound-sign (#) are comments, and are ignored.
@@ -67,8 +68,8 @@
 line of the crontab's owner.
 HOME and SHELL may be overridden by settings in the crontab; LOGNAME may not.
 .PP
-(Another note: the LOGNAME variable is sometimes called USER on BSD systems...
-on these systems, USER will be set also.)
+(Another note:  the LOGNAME variable is sometimes called USER on BSD
+systems and on these systems, USER will be set also.)
 .PP
 In addition to LOGNAME, HOME, and SHELL,
 .IR cron (8)
@@ -90,16 +91,16 @@
 .PP
 The CRON_WITHIN variable should indicate the number of seconds
 within a job's scheduled time that it should still be run.  On a
-heavily loaded system, or on a system that has just been "woken
-up", jobs will sometimes start later than originally intended, and
+heavily loaded system, or on a system that has just been ``woken
+up'', jobs will sometimes start later than originally intended, and
 by skipping non-critical jobs because of delays, system load can
 be lightened.  If CRON_WITHIN is defined but empty (CRON_WITHIN="") or
 set to some non-positive value (0, a negative number, or a non-numeric
 string), it is treated as if it was unset.
 .PP
-The format of a cron command is very much the V7 standard, with a number of
-upward-compatible extensions.  Each line has five time and date fields,
-followed by a user name if this is the system crontab file,
+The format of a crontab entry is very much the V7 standard, with a
+number of upward-compatible extensions.  Each line has five time and
+date fields, followed by a user name if this is the system crontab file,
 followed by a command.  Commands are executed by
 .IR cron (8)
 when the minute, hour, and month of year fields match the current time,
@@ -136,7 +137,7 @@
 and 11.
 .PP
 Lists are allowed.  A list is a set of numbers (or ranges)
-separated by commas.  Examples: ``1,2,5,9'', ``0-4,8-12''.
+separated by commas.  Examples:  ``1,2,5,9'', ``0-4,8-12''.
 .PP
 Step values can be used in conjunction with ranges.  Following
 a range with ``/\*[Lt]number\*[Gt]'' specifies skips of the number's value
@@ -151,17 +152,21 @@
 day or month (case doesn't matter).  Ranges or
 lists of names are not allowed.
 .PP
-The ``sixth'' field (the rest of the line) specifies the command to be
-run.
-The entire command portion of the line, up to a newline or %
-character, will be executed by /bin/sh or by the shell
-specified in the SHELL variable of the cronfile.
-Percent-signs (%) in the command, unless escaped with backslash
-(\\), will be changed into newline characters, and all data
-after the first % will be sent to the command as standard
-input.
+On BSD systems the system crontab file (/etc/crontab) has a ``username''
+field after the time and date fields.  The user name given in this field
+tells
+.I cron
+what user to execute the command as.
+.PP
+The ``last'' field (the rest of the line) specifies the command to be
+run.  The entire command portion of the line, up to a newline or %
+character, will be executed by /bin/sh or by the shell specified in the
+SHELL variable of the cronfile.  Percent-signs (%) in the command,
+unless escaped with backslash (\\), will be changed into newline
+characters, and all data after the first % will be sent to the command
+as standard input.
 .PP
-Note: The day of a command's execution can be specified by two
+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
 restricted (ie, aren't *), the command will be run when
 .I either
@@ -179,7 +184,7 @@
 .br
 ------	-------
 .br
-@reboot	Run once, at startup.
+@reboot	Run once, at startup.  (Caution, not just at system reboot)
 .br
 @yearly	Run once a year, "0 0 1 1 *".
 .br
@@ -195,24 +200,33 @@
 .br
 @hourly	Run once an hour, "0 * * * *".
 .br
-.SH EXAMPLE CRON FILE
+.ta 0
+.SH "EXAMPLE CRON FILE"
+.ta 2.25i
 .nf
-
+#
 # use /bin/sh to run commands, no matter what /etc/passwd says
 SHELL=/bin/sh
 # mail any output to `paul', no matter whose crontab this is
 MAILTO=paul
 #
+#mm hh mday mon wday	command
+#
 # run five minutes after midnight, every day
-5 0 * * *       $HOME/bin/daily.job \*[Gt]\*[Gt] $HOME/tmp/out 2\*[Gt]\*[Am]1
+5 0 * * *	$HOME/bin/daily.job \*[Gt]\*[Gt] $HOME/tmp/out 2\*[Gt]\*[Am]1
+#
 # run at 2:15pm on the first of every month -- output mailed to paul
-15 14 1 * *     $HOME/bin/monthly
-# run at 10 pm on weekdays, annoy Joe
-0 22 * * 1-5    mail -s "It's 10pm" joe%Joe,%%Where are your kids?%
+15 14 1 * *	$HOME/bin/monthly
+#
+# run at 10 pm on weekdays, annoy Joe (note message body fed to command)
+0 22 * * 1-5	mail -s "It's 10pm" joe%Joe,%%Where are your kids?%
+#
 23 0-23/2 * * * echo "run 23 minutes after midn, 2am, 4am ..., everyday"
-5 4 * * sun     echo "run at 5 after 4 every sunday"
+#
+5 4 * * sun	echo "run at 5 after 4 every sunday"
+.ta 0
 .fi
-.SH SEE ALSO
+.SH "SEE ALSO"
 cron(8), crontab(1)
 .SH EXTENSIONS
 When specifying day of week, both day 0 and day 7 will be considered Sunday.
@@ -228,6 +242,9 @@
 Environment variables can be set in the crontab.  In BSD or ATT, the
 environment handed to child processes is basically the one from /etc/rc.
 .PP
+Command input is allowed with '%' as newline in the crontab entry (SysV
+can't do this).
+.PP
 Command output is mailed to the crontab owner (BSD can't do this), can be
 mailed to a person other than the crontab owner (SysV can't do this), or the
 feature can be turned off and no mail will be sent at all (SysV can't do this
Index: usr.sbin/cron/crontab.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.sbin/cron/crontab.c,v
retrieving revision 1.30
diff -u -r1.30 crontab.c
--- usr.sbin/cron/crontab.c	24 May 2006 21:43:43 -0000	1.30
+++ usr.sbin/cron/crontab.c	28 May 2007 20:22:49 -0000
@@ -35,7 +35,7 @@
 #define MAXCRONTABSIZE	(1024*256)	/* max crontab size == 256 KB */
 
 
-#define	MAIN_PROGRAM
+#define	MAIN_PROGRAM	"CRONTAB"
 
 
 #include "cron.h"
@@ -54,6 +54,9 @@
 #endif
 #include <time.h>
 #include <signal.h>
+#if defined(SYSLOG)
+# include <syslog.h>
+#endif
 
 
 #define NHEADER_LINES 3
@@ -121,7 +124,7 @@
 			"You (%s) are not allowed to use this program (%s)\n",
 			User, getprogname());
 		fprintf(stderr, "See crontab(1) for more information\n");
-		log_it(RealUser, Pid, "AUTH", "crontab command not allowed");
+		log_it(LOG_NOTICE, RealUser, Pid, "AUTH", "crontab command not allowed");
 		exit(ERROR_EXIT);
 	}
 	exitstatus = OK_EXIT;
@@ -280,7 +283,7 @@
 	FILE	*f;
 	int	ch;
 
-	log_it(RealUser, Pid, "LIST", User);
+	log_it(LOG_INFO, RealUser, Pid, "LIST", User);
 	(void) snprintf(n, sizeof(n), CRON_TAB(User));
 	if (!(f = fopen(n, "r"))) {
 		if (errno == ENOENT)
@@ -304,7 +307,7 @@
 delete_cmd(void) {
 	char	n[MAX_FNAME];
 
-	log_it(RealUser, Pid, "DELETE", User);
+	log_it(LOG_INFO, RealUser, Pid, "DELETE", User);
 	(void) snprintf(n, sizeof(n), CRON_TAB(User));
 	if (unlink(n)) {
 		if (errno == ENOENT)
@@ -338,7 +341,7 @@
 	sig_t		oint, oabrt;
 	char		*edit;
 
-	log_it(RealUser, Pid, "BEGIN EDIT", User);
+	log_it(LOG_DEBUG, RealUser, Pid, "BEGIN EDIT", User);
 	(void) snprintf(n, sizeof(n), CRON_TAB(User));
 	if (!(f = fopen(n, "r"))) {
 		if (errno != ENOENT) {
@@ -439,6 +442,7 @@
 		/*NOTREACHED*/
 	default:
 		/* parent */
+		/* XXX ignore signals until child returns XXX */
 		break;
 	}
 	/* parent */
@@ -500,7 +504,7 @@
  remove:
 	unlink(Filename);
  done:
-	log_it(RealUser, Pid, "END EDIT", User);
+	log_it(LOG_INFO, RealUser, Pid, "END EDIT", User);
 }
 	
 
@@ -661,7 +665,7 @@
 		warn("error renaming %s to %s", tn, n);
 		goto out;
 	}
-	log_it(RealUser, Pid, "REPLACE", User);
+	log_it(LOG_INFO, RealUser, Pid, "REPLACE", User);
 
 	poke_daemon();
 	free(envp);
Index: usr.sbin/cron/database.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.sbin/cron/database.c,v
retrieving revision 1.7
diff -u -r1.7 database.c
--- usr.sbin/cron/database.c	16 Mar 2005 02:53:55 -0000	1.7
+++ usr.sbin/cron/database.c	28 May 2007 20:22:49 -0000
@@ -34,13 +34,16 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/file.h>
+#if defined(SYSLOG)
+# include <syslog.h>
+#endif
 
 
 #define TMAX(a,b) ((a)>(b)?(a):(b))
 
 
 static	void		process_crontab(const char *, const char *,
-					const char *, struct stat *,
+					char *, struct stat *,
 					cron_db *, cron_db *);
 
 
@@ -61,13 +64,13 @@
 	 * cached any of the database), we'll see the changes next time.
 	 */
 	if (stat(SPOOL_DIR, &statbuf) < OK) {
-		log_it("CRON", getpid(), "STAT FAILED", SPOOL_DIR);
+		log_it(LOG_ERR, "CRON", getpid(), "STAT FAILED", SPOOL_DIR);
 		(void) exit(ERROR_EXIT);
 	}
 
 	/* track system crontab file
 	 */
-	if (stat(SYSCRONTAB, &syscron_stat) < OK)
+	if (stat(syscron_name, &syscron_stat) < OK)
 		syscron_stat.st_mtime = 0;
 
 	/* if spooldir's mtime has not changed, we don't need to fiddle with
@@ -92,8 +95,7 @@
 	new_db.head = new_db.tail = NULL;
 
 	if (syscron_stat.st_mtime) {
-		process_crontab("root", NULL, SYSCRONTAB, &syscron_stat,
-		    &new_db, old_db);
+		process_crontab("root", (char *) NULL, syscron_name, &syscron_stat, &new_db, old_db);
 	}
 
 	/* we used to keep this dir open all the time, for the sake of
@@ -101,7 +103,7 @@
 	 * we fork a lot more often than the mtime of the dir changes.
 	 */
 	if (!(dir = opendir(SPOOL_DIR))) {
-		log_it("CRON", getpid(), "OPENDIR FAILED", SPOOL_DIR);
+		log_it(LOG_ERR, "CRON", getpid(), "OPENDIR FAILED", SPOOL_DIR);
 		(void) exit(ERROR_EXIT);
 	}
 
@@ -189,7 +191,7 @@
 
 
 static void
-process_crontab(const char *uname, const char *fname, const char *tabname,
+process_crontab(const char *uname, const char *fname, char *tabname,
                 struct stat *statbuf, cron_db *new_db, cron_db *old_db)
 {
 	struct passwd	*pw = NULL;
@@ -203,19 +205,20 @@
 	} else if ((pw = getpwnam(uname)) == NULL) {
 		/* file doesn't have a user in passwd file.
 		 */
-		log_it(fname, getpid(), "ORPHAN", "no passwd entry");
+		log_it(LOG_WARNING, fname, getpid(), "ORPHAN", "no passwd entry");
 		goto next_crontab;
 	}
 
+	Set_FileName(tabname)
 	if ((crontab_fd = open(tabname, O_RDONLY, 0)) < OK) {
 		/* crontab not accessible?
 		 */
-		log_it(fname, getpid(), "CAN'T OPEN", tabname);
+		log_it(LOG_WARNING, fname, getpid(), "CAN'T OPEN", tabname);
 		goto next_crontab;
 	}
 
 	if (fstat(crontab_fd, statbuf) < OK) {
-		log_it(fname, getpid(), "FSTAT FAILED", tabname);
+		log_it(LOG_WARNING, fname, getpid(), "FSTAT FAILED", tabname);
 		goto next_crontab;
 	}
 
@@ -242,7 +245,7 @@
 		Debug(DLOAD, (" [delete old data]"))
 		unlink_user(old_db, u);
 		free_user(u);
-		log_it(fname, getpid(), "RELOAD", tabname);
+		log_it(LOG_INFO, fname, getpid(), "RELOAD", tabname);
 	}
 	u = load_user(crontab_fd, pw, fname);
 	if (u != NULL) {
@@ -254,5 +257,6 @@
 	if (crontab_fd >= OK) {
 		Debug(DLOAD, (" [done]\n"))
 		close(crontab_fd);
+		Set_FileName((char *) NULL)
 	}
 }
Index: usr.sbin/cron/do_command.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.sbin/cron/do_command.c,v
retrieving revision 1.25
diff -u -r1.25 do_command.c
--- usr.sbin/cron/do_command.c	18 Dec 2006 20:11:10 -0000	1.25
+++ usr.sbin/cron/do_command.c	28 May 2007 20:22:49 -0000
@@ -61,7 +61,7 @@
 	 */
 	switch (fork()) {
 	case -1:
-		log_it("CRON",getpid(),"error","can't fork");
+		log_it(LOG_ERR, "CRON", getpid(), "error", "can't fork");
 		break;
 	case 0:
 		/* child process */
@@ -164,7 +164,7 @@
 	 */
 	switch (vfork()) {
 	case -1:
-		log_it("CRON",getpid(),"error","can't vfork");
+		log_it(LOG_ERR, "CRON", getpid(), "error", "can't vfork");
 		exit(ERROR_EXIT);
 		/*NOTREACHED*/
 	case 0:
@@ -179,7 +179,7 @@
 		/*local*/{
 			char *x = mkprints((u_char *)e->cmd, strlen(e->cmd));
 
-			log_it(usernm, getpid(), "CMD START", x);
+			log_it(LOG_INFO, usernm, getpid(), "CMD START", x);
 			free(x);
 		}
 
@@ -480,7 +480,7 @@
 			"mailed %d byte%s of output but got status 0x%04x\n",
 					bytes, (bytes==1)?"":"s",
 					status);
-				log_it(usernm, getpid(), "MAIL", buf);
+				log_it(LOG_INFO, usernm, getpid(), "MAIL", buf);
 			}
 
 		} /*if data from grandchild*/
@@ -516,7 +516,7 @@
 	/*local*/{
 		char *x = mkprints((u_char *)e->cmd, strlen(e->cmd));
 
-		log_it(usernm, getpid(), "CMD FINISH", x);
+		log_it(LOG_INFO, usernm, getpid(), "CMD FINISH", x);
 		free(x);
 	}
 }
Index: usr.sbin/cron/entry.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.sbin/cron/entry.c,v
retrieving revision 1.8
diff -u -r1.8 entry.c
--- usr.sbin/cron/entry.c	16 Mar 2005 02:53:55 -0000	1.8
+++ usr.sbin/cron/entry.c	28 May 2007 20:22:49 -0000
@@ -85,8 +85,10 @@
 	 * syntax:
 	 *   user crontab:
 	 *	minutes hours doms months dows cmd\n
-	 *   system crontab (/etc/crontab):
+	 *   BSD system crontab (/etc/crontab):
 	 *	minutes hours doms months dows USERNAME cmd\n
+	 *   UNIX system crontab (/etc/crontab):
+	 *	minutes hours doms months dows cmd\n
 	 */
 
 	ecode_e	ecode = e_none;
@@ -229,6 +231,11 @@
 	/* ch is the first character of a command, or a username */
 	unget_char(ch, file);
 
+#if defined(BSD)
+	/*
+	 * BSD /etc/crontab (the system crontab) has an extra field, the
+	 * username, before the command.
+	 */
 	if (!pw) {
 		char		*username = cmd;	/* temp buffer */
 
@@ -244,10 +251,12 @@
 		pw = getpwnam(username);
 		if (pw == NULL) {
 			ecode = e_username;
+			Debug(DPARS, ("load_entry()...invalid username\n"))
 			goto eof;
 		}
 		Debug(DPARS, ("load_entry()...uid %d, gid %d\n",e->uid,e->gid))
 	}
+#endif
 
 	e->uid = pw->pw_uid;
 	e->gid = pw->pw_gid;
Index: usr.sbin/cron/env.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.sbin/cron/env.c,v
retrieving revision 1.15
diff -u -r1.15 env.c
--- usr.sbin/cron/env.c	7 Jun 2005 13:43:52 -0000	1.15
+++ usr.sbin/cron/env.c	28 May 2007 20:22:49 -0000
@@ -107,8 +107,12 @@
 }
 
 
-/* return	ERR = end of file
- *		FALSE = not an env setting (file was repositioned)
+/*
+ * Load an environment variable from 'f'.
+ *
+ * return	ERR = end of file
+ *		FALSE = not an env setting
+ *			NOTE: file is repositioned to where we started from.
  *		TRUE = was an env setting
  */
 int
@@ -116,8 +120,10 @@
 {
 	long	filepos;
 	int	fileline, len;
-	char	*name, *name_end, *val, *equal;
-	char	*s;
+	char	*name = NULL;
+	char	*name_end = NULL;
+	char	*val, *equal;
+	char	*s = NULL;
 
 	s = name = name_end = NULL;	/* XXXGCC -Wuninitialized [sparc64] */
 
Index: usr.sbin/cron/job.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.sbin/cron/job.c,v
retrieving revision 1.6
diff -u -r1.6 job.c
--- usr.sbin/cron/job.c	16 Mar 2005 02:53:55 -0000	1.6
+++ usr.sbin/cron/job.c	28 May 2007 20:22:49 -0000
@@ -32,9 +32,10 @@
 #endif
 #endif
 
-
 #include "cron.h"
-
+#if defined(SYSLOG)
+# include <syslog.h>
+#endif
 
 typedef	struct _job {
 	struct _job	*next;
@@ -90,7 +91,7 @@
 			    strlen(j->e->cmd));
 			char *usernm = env_get("LOGNAME", j->e->envp);
 
-			log_it(usernm, getpid(), "CMD (skipped)", x);
+			log_it(LOG_INFO, usernm, getpid(), "CMD (skipped)", x);
 			free(x);
 		}
 		jn = j->next;
Index: usr.sbin/cron/misc.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.sbin/cron/misc.c,v
retrieving revision 1.13
diff -u -r1.13 misc.c
--- usr.sbin/cron/misc.c	21 May 2006 19:26:43 -0000	1.13
+++ usr.sbin/cron/misc.c	28 May 2007 20:22:49 -0000
@@ -272,7 +272,7 @@
 				"can't open or create %s: %s",
 				pidfile, strerror(errno));
 			warnx(buf);
-			log_it("CRON", getpid(), "DEATH", buf);
+			log_it(LOG_ERR, "CRON", getpid(), "DEATH", buf);
 			exit(ERROR_EXIT);
 		}
 
@@ -284,7 +284,7 @@
 				"can't lock %s, otherpid may be %d: %s",
 				pidfile, otherpid, strerror(save_errno));
 			warnx(buf);
-			log_it("CRON", getpid(), "DEATH", buf);
+			log_it(LOG_ERR, "CRON", getpid(), "DEATH", buf);
 			exit(ERROR_EXIT);
 		}
 
@@ -451,18 +451,18 @@
 
 
 void
-log_it(const char *username, int xpid, const char *event, const char *detail)
+log_it(int priority, const char *username, int xpid, const char *event, const char *detail)
 {
-	PID_T			pid = xpid;
+	PID_T		pid = xpid;
 #if defined(LOG_FILE)
-	char			*msg;
-	size_t			msglen;
-	TIME_T			now = time((TIME_T) 0);
+	char		*msg;
+	size_t		msglen;
+	TIME_T		now = time((TIME_T) 0);
 	struct tm	*t = localtime(&now);
 #endif /*LOG_FILE*/
 
 #if defined(SYSLOG)
-	static int		syslog_open = 0;
+	static int	syslog_open = 0;
 #endif
 
 #if defined(LOG_FILE)
@@ -503,10 +503,6 @@
 
 #if defined(SYSLOG)
 	if (!syslog_open) {
-		/* we don't use LOG_PID since the pid passed to us by
-		 * our client may not be our own.  therefore we want to
-		 * print the pid ourselves.
-		 */
 # ifdef LOG_DAEMON
 		openlog(getprogname(), LOG_PID, LOG_CRON);
 # else
@@ -515,21 +511,25 @@
 		syslog_open = TRUE;		/* assume openlog success */
 	}
 
-	syslog(LOG_INFO, "(%s) %s (%s)\n", username, event, detail);
+	if (getpid() != pid)			/* getpid() is fast enough */
+		syslog(priority, "(%s)[%d] %s (%s)\n", username, pid, event, detail);
+	else
+		syslog(priority, "(%s) %s (%s)\n", username, event, detail);
 
 #endif /*SYSLOG*/
 
 #if DEBUGGING
 	if (DebugFlags) {
-		fprintf(stderr, "log_it: (%s %d) %s (%s)\n",
-			username, pid, event, detail);
+		fprintf(stderr, "log_it: (%d, %s, %d) %s (%s)\n",
+			priority, username, pid, event, detail);
 	}
 #endif
 }
 
 
 void
-log_close(void) {
+log_close(void)
+{
 	if (LogFD != ERR) {
 		close(LogFD);
 		LogFD = ERR;
Index: usr.sbin/cron/user.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.sbin/cron/user.c,v
retrieving revision 1.4
diff -u -r1.4 user.c
--- usr.sbin/cron/user.c	16 Mar 2005 02:53:55 -0000	1.4
+++ usr.sbin/cron/user.c	28 May 2007 20:22:49 -0000
@@ -31,6 +31,13 @@
 
 
 #include "cron.h"
+#include <errno.h>
+#if defined(SYSLOG)
+# include <syslog.h>
+#endif
+
+
+static void	load_user_error(const char *);
 
 
 void
@@ -59,7 +66,7 @@
 	char	**envp;
 
 	if (!(file = fdopen(crontab_fd, "r"))) {
-		perror("fdopen on crontab_fd in load_user");
+		log_it(LOG_WARNING, "CRON", getpid(), "fdopen on crontab_fd in load_user", strerror(errno));
 		return NULL;
 	}
 
@@ -86,7 +93,7 @@
 			u = NULL;
 			goto done;
 		case FALSE:
-			e = load_entry(file, NULL, pw, envp);
+			e = load_entry(file, load_user_error, pw, envp);
 			if (e) {
 				e->next = u->crontab;
 				u->crontab = e;
@@ -104,3 +111,19 @@
 	Debug(DPARS, ("...load_user() done\n"))
 	return u;
 }
+
+
+static void
+load_user_error(const char *msg)
+{
+	char *pmsg;
+
+	if (-1 == asprintf(&pmsg, "error in crontab %s at line %d", FileName, LineNumber)) {
+		Debug(DLOAD, ("... out of memory formatting error message: %s!\n",
+			      strerror(errno)))
+		log_it(LOG_ERR, "CRON", getpid(), "OUT OF MEMORY", msg);
+	} else
+		log_it(LOG_INFO, "CRON", getpid(), pmsg, msg);
+	if (pmsg)
+		free(pmsg);
+}

>Unformatted: