Subject: Cron runs weekly jobs nightly (#423)
Index:	usr.sbin/cron/entry.c 2.11BSD

Description:
	cron(8) runs weekly jobs (scheduled only for day 6) nightly.

Repeat-By:
	1. Have the following entry in /etc/crontab file (or omit the
	   "user" field if the entry is placed in a user's crontab).
	   Adjust the minute and hour field to be conveniently in the near
	   future (and use a day other than 6 if running this test on a
	   Saturday ;)):

0 9 * * * root echo "The first command"
2 9 * * 6 root echo "The second command"

	Note that you will receive two mail items a couple minutes apart
	because not only did the hourly job run but so did the weekly one!

Fix:
	There were a total of 4 bugs found dating back to 1994 (these are
	not things I broke during the port to 2.11BSD).  Fortunately only
	one of them was "fatal" and generated unexpected results.

	1)  The use of the bit_nclear() macro in entry.c had a bogus
	    "+1" in it to deal with 0 origined numbers.  BUT, the bit_nclear
	    macro already had "+1" logic in it.  The result was that one
	    two many bits were cleared.

	    On systems where the C compiler aligned 'int' structure members
	    on a 4 byte boundary clearing an extra bit in a "pad byte" was
	    harmless (still an error though).  But on a 16 bit machine where
	    the alignment requirement is only 2 bytes clearing an extra bit
	    would (and in this case _did_) clear the first bit of the next
	    structure member.   In this case the "DOW_STAR" flag bit was
	    being cleared which resulted in cron running the weekly job
	    every day.

	2)  The definition of 'bit_alloc' was calling malloc(3) with
	    two arguments.  Luckily noone uses 'bit_alloc' but the error
	    was fixed anyhow by using 'calloc' instead of 'malloc'.

	3) The sigblock() return value in cron_pclose() was being assigned
	   to an 'int'.  This is incorrect since "sizeof int != sizeof long".
	   A 'long' would have been better but since 'sigset_t' now exists
	   it was used.

	4) In crontab one of the 'swap_uids' calls should have been
	   'swap_uids_back'.  On a system which has 'SAVED_UIDS' calling
	   'swap_uids' and 'swap_uids_back' are _NOT_ the same thing.  Only
	   on systems which use 'setreuid' (those which do not have SAVED_UIDS)
	   are 'swap_uids' and 'swap_uids_back' a "toggle".

	To install this update cut where indicated saving to a file (/tmp/423)
	and then:

		kill the currently running cron process 
		  ps | grep cron
		  kill _cron_pid_

		patch -p0 < /tmp/423
		cd /usr/src/usr.sbin/cron
		make clean
		make
		make install
		make clean
		cron

	As always this and previous updates to 2.11BSD are available via
	anonymous FTP to either FTP.IIPO.GTEGSC.COM or MOE.2BSD.COM in the
	directory /pub/2.11BSD.

----------------------------cut here---------------------
*** /usr/src/usr.sbin/cron/README.2BSD.old	Fri Jun 18 19:53:04 1999
--- /usr/src/usr.sbin/cron/README.2BSD	Mon Aug  9 21:32:02 1999
***************
*** 1,5 ****
--- 1,19 ----
  	This is the 2.11BSD port of the 'Vixie cron-3.0 patch1'.  
  	
+ 	Updated 1999/8/9: Fix an off by one condition in entry.c that was
+ 	causing the 'dow' (day of week) bitmap to be overrun by one bit.
+ 	Properly ifdef'd some rcs/sccs id strings so that they do not get
+ 	compiled in (data space is at a premium on a 16 bit machine).  Fix
+ 	a bug in bitstring.h (fortunately nothing uses the macro bit_alloc
+ 	at this time) that was using 'malloc' with two arguments.  Do some
+ 	minor cosmetic cleanup (trailing and extra blank lines, etc).  Fix
+ 	the sigmask handling in cron_pclose() - it was using 'int' as the
+ 	signal mask type instead of 'long' or more properly 'sigmask_t'.
+ 	In addition to fixing the sigmask type the code was revised to use 
+ 	modern signal and wait calls.  In crontab one of the 'swap_uids' 
+ 	calls should have been 'swap_uids_back' in case "SAVED_UIDS" is
+ 	supported by the system.
+ 
  	The files Part01, Part02 and Patch01 were retrieved from 
  	ftp://ftp.vix.com/pub/vixie/cron-3.0/ 
  
*** /usr/src/usr.sbin/cron/bitstring.h.old	Sat Jun 12 10:08:40 1999
--- /usr/src/usr.sbin/cron/bitstring.h	Thu Aug  5 20:43:41 1999
***************
*** 17,23 ****
   * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   *
!  *	@(#)bitstring.h	5.2 (Berkeley) 4/4/90
   */
  
  typedef	unsigned char bitstr_t;
--- 17,23 ----
   * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   *
!  *	@(#)bitstring.h	5.2.1 (2.11BSD) 1999/8/5
   */
  
  typedef	unsigned char bitstr_t;
***************
*** 38,44 ****
  
  				/* allocate a bitstring */
  #define	bit_alloc(nbits) \
! 	(bitstr_t *)malloc(1, \
  	    (unsigned int)bitstr_size(nbits) * sizeof(bitstr_t))
  
  				/* allocate a bitstring on the stack */
--- 38,44 ----
  
  				/* allocate a bitstring */
  #define	bit_alloc(nbits) \
! 	(bitstr_t *)calloc(1, \
  	    (unsigned int)bitstr_size(nbits) * sizeof(bitstr_t))
  
  				/* allocate a bitstring on the stack */
*** /usr/src/usr.sbin/cron/cron.c.old	Tue Jun 15 21:11:15 1999
--- /usr/src/usr.sbin/cron/cron.c	Thu Aug  5 20:48:36 1999
***************
*** 15,27 ****
   * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
   */
  
! #if !defined(lint) && !defined(LINT)
! static char rcsid[] = "$Id: cron.c,v 2.11 1994/01/15 20:43:43 vixie Exp $";
  #endif
  
- 
  #define	MAIN_PROGRAM
- 
  
  #include "cron.h"
  #include <sys/signal.h>
--- 15,25 ----
   * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
   */
  
! #if !defined(lint) && defined(DOSCCS)
! static char sccsid[] = "@(#)cron.c 2.11.1 (2.11BSD) 1999/08/05";
  #endif
  
  #define	MAIN_PROGRAM
  
  #include "cron.h"
  #include <sys/signal.h>
*** /usr/src/usr.sbin/cron/crontab.c.old	Tue Jun 15 21:11:42 1999
--- /usr/src/usr.sbin/cron/crontab.c	Mon Aug  9 21:55:29 1999
***************
*** 15,23 ****
   * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
   */
  
! #if !defined(lint) && !defined(LINT)
! static char rcsid[] = "$Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $";
! #endif
  
  /* crontab - install and manage per-user crontab files
   * vix 02may87 [RCS has the rest of the log]
--- 15,21 ----
   * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
   */
  
! static char sccsid[] = "@(#) crontab.c 2.13.1 (2.11BSD) 1999/8/9";
  
  /* crontab - install and manage per-user crontab files
   * vix 02may87 [RCS has the rest of the log]
***************
*** 24,33 ****
   * vix 26jan87 [original]
   */
  
- 
  #define	MAIN_PROGRAM
  
- 
  #include "cron.h"
  #include <errno.h>
  #include <fcntl.h>
--- 22,29 ----
***************
*** 212,218 ****
  				perror(Filename);
  				exit(ERROR_EXIT);
  			}
! 			if (swap_uids() < OK) {
  				perror("swapping uids back");
  				exit(ERROR_EXIT);
  			}
--- 208,214 ----
  				perror(Filename);
  				exit(ERROR_EXIT);
  			}
! 			if (swap_uids_back() < OK) {
  				perror("swapping uids back");
  				exit(ERROR_EXIT);
  			}
***************
*** 492,498 ****
  	 */
  	fprintf(tmp, "# DO NOT EDIT THIS FILE - edit the master and reinstall.\n");
  	fprintf(tmp, "# (%s installed on %-24.24s)\n", Filename, ctime(&now));
! 	fprintf(tmp, "# (Cron version -- %s)\n", rcsid);
  
  	/* copy the crontab to the tmp
  	 */
--- 488,494 ----
  	 */
  	fprintf(tmp, "# DO NOT EDIT THIS FILE - edit the master and reinstall.\n");
  	fprintf(tmp, "# (%s installed on %-24.24s)\n", Filename, ctime(&now));
! 	fprintf(tmp, "# (Cron version -- %s)\n", sccsid);
  
  	/* copy the crontab to the tmp
  	 */
*** /usr/src/usr.sbin/cron/entry.c.old	Tue Jun 15 21:11:55 1999
--- /usr/src/usr.sbin/cron/entry.c	Thu Aug  5 20:51:31 1999
***************
*** 15,22 ****
   * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
   */
  
! #if !defined(lint) && !defined(LINT)
! static char rcsid[] = "$Id: entry.c,v 2.12 1994/01/17 03:20:37 vixie Exp $";
  #endif
  
  /* vix 26jan87 [RCS'd; rest of log is in RCS file]
--- 15,22 ----
   * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
   */
  
! #if !defined(lint) && defined(DOSCCS)
! static char sccsid[] = "@(#)entry.c 2.12.2 (2.11BSD) 1999/08/05";
  #endif
  
  /* vix 26jan87 [RCS'd; rest of log is in RCS file]
***************
*** 25,34 ****
   * vix 30dec86 [written]
   */
  
- 
  #include "cron.h"
  
- 
  typedef	enum ecode {
  	e_none, e_minute, e_hour, e_dom, e_month, e_dow,
  	e_cmd, e_timespec, e_username
--- 25,32 ----
***************
*** 322,330 ****
  	/* list = range {"," range}
  	 */
  	
! 	/* clear the bit string, since the default is 'off'.
  	 */
! 	bit_nclear(bits, 0, (high-low+1));
  
  	/* process all ranges
  	 */
--- 320,329 ----
  	/* list = range {"," range}
  	 */
  	
! 	/* clear the bit string, since the default is 'off'.  DONT add an
! 	 * extra bit here, that's done in the macro!
  	 */
! 	bit_nclear(bits, 0, (high-low));
  
  	/* process all ranges
  	 */
*** /usr/src/usr.sbin/cron/popen.c.old	Sat Jun 12 10:08:40 1999
--- /usr/src/usr.sbin/cron/popen.c	Thu Aug  5 20:49:35 1999
***************
*** 23,37 ****
   * globbing stuff since we don't need it.  also execvp instead of execv.
   */
  
! #ifndef lint
! static char rcsid[] = "$Id: popen.c,v 1.5 1994/01/15 20:43:43 vixie Exp $";
! static char sccsid[] = "@(#)popen.c	5.7 (Berkeley) 2/14/89";
! #endif /* not lint */
  
  #include "cron.h"
  #include <sys/signal.h>
  
- 
  #define WANT_GLOBBING 0
  
  /*
--- 23,36 ----
   * globbing stuff since we don't need it.  also execvp instead of execv.
   */
  
! #if	!defined(lint) && defined(DOSCCS)
! static char sccsid[] = "@(#)popen.c	5.7.2 (2.11BSD) 1999/08/05";
! #endif
  
  #include "cron.h"
+ #include <errno.h>
  #include <sys/signal.h>
  
  #define WANT_GLOBBING 0
  
  /*
***************
*** 146,154 ****
  	FILE *iop;
  {
  	register int fdes;
! 	int omask;
  	WAIT_T stat_loc;
! 	PID_T pid;
  
  	/*
  	 * pclose returns -1 if stream is not associated with a
--- 145,153 ----
  	FILE *iop;
  {
  	register int fdes;
! 	sigset_t omask, nmask;
  	WAIT_T stat_loc;
! 	register PID_T pid;
  
  	/*
  	 * pclose returns -1 if stream is not associated with a
***************
*** 157,166 ****
  	if (pids == 0 || pids[fdes = fileno(iop)] == 0)
  		return(-1);
  	(void)fclose(iop);
! 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
! 	while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1)
! 		;
! 	(void)sigsetmask(omask);
  	pids[fdes] = 0;
  	return (pid == -1 ? -1 : WEXITSTATUS(stat_loc));
  }
--- 156,170 ----
  	if (pids == 0 || pids[fdes = fileno(iop)] == 0)
  		return(-1);
  	(void)fclose(iop);
! 	sigemptyset(&nmask);
! 	sigaddset(&nmask, SIGINT);
! 	sigaddset(&nmask, SIGQUIT);
! 	sigaddset(&nmask, SIGHUP);
! 	sigprocmask(SIG_BLOCK, &nmask, &omask);
! 	do	{
! 		pid = waitpid(pids[fdes], &stat_loc, NULL);
! 		} while (pid == -1 && errno == EINTR);
! 	(void)sigprocmask(SIG_SETMASK, &omask, NULL);
  	pids[fdes] = 0;
  	return (pid == -1 ? -1 : WEXITSTATUS(stat_loc));
  }
*** /VERSION.old	Tue Jul 20 20:14:15 1999
--- /VERSION	Thu Aug  5 20:59:43 1999
***************
*** 1,5 ****
! Current Patch Level: 422
! Date: July 20, 1999
  
  2.11 BSD
  ============
--- 1,5 ----
! Current Patch Level: 423
! Date: August 5, 1999
  
  2.11 BSD
  ============
