From: skb@ute-cmi.ctcpc.cypress.com (Scott Butler, MN, x5036, (612) 894-6562)
Newsgroups: alt.sys.sun
Subject: Re: "Spring Forward" hurt cron -FIX
Date: 15 Apr 92 18:01:42 GMT
Reply-To: skb@ute-cmi.ctcpc.cypress.com
Organization: Cypress Semiconductor Inc.

Enclosed is a "FIX" for the DST cron bug, and info for where
to get the patch.  I obtained both of these from the 
sun-managers mailing list.  (To get on sun-managers post
a request to sun-managers-request@eecs.nwu.edu)

Now the "FIX" from knutson@sw.mcc.com (Jim Knutson).
(I have not personally tried this since
my systems all went down shortly after DST and were
rebooted anyway...)

> I wrote this and posted it a year ago for just this problem.
> Sounds like it's time for a repost.  Sorry if this violates the rules.
> 
> Just install it, run it as root, and you're set.
> You need to set the TIMEZONE you are in when
> you install dstcronfix.  If you have a the localtime timezone file
> linked to your timezone, then you can set TIMEZONE to `localtime' and
> it should work no matter what timezone you have set.
> 
> Jim

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by knutson on Mon Mar 30 11:41:49 CST 1992
# Contents:  dstcronfix
 
echo x - dstcronfix
sed 's/^@//' > "dstcronfix" <<'@//E*O*F dstcronfix//'
#!/bin/sh
# @(#)dstcronfix	1.3	4/15/91
#
# NAME
#	dstcronfix - restart cron when DST changes
#
# SYNOPSIS
#	dstcronfix
#
# DESCRIPTION
#	dstcronfix determines when the next DST change takes place and
#	then schedules an at job to restart cron after the change has
#	taken place.
#
#	The at job is scheduled to start just before the time change.
#	It then waits until the time change has occured before killing
#	and restarting cron.  It also reschedules itself for the next 
#	DST change.
#
#	The leadtime for scheduling is set in the script and should be
#	set to a value which will allow cron to run it before the DST
#	change occurs.  For SunOS 4.0 and greater, at/cron have a 1
#	minute granularity.  Other systems which execute atrun from
#	cron must set the lead time to account for the granularity in
#	running atrun.
#
# SEE ALSO
#	at(1), cron(8), zdump(8)
#
# AUTHOR
#	Jim Knutson <knutson@mcc.com>
#
# BUGS
#	Restarts cron twice in the fall.
#
TIMEZONE=US/Central
LEADTIME=1			# number of minutes of lead time
TMP=/tmp/.dst$$
PATH=/usr/bin:/usr/ucb:/usr/etc

# return month number for a given month name
monthnum() {
	case "$1" in
	Jan) echo 01;;
	Feb) echo 02;;
	Mar) echo 03;;
	Apr) echo 04;;
	May) echo 05;;
	Jun) echo 06;;
	Jul) echo 07;;
	Aug) echo 08;;
	Sep) echo 09;;
	Oct) echo 10;;
	Nov) echo 11;;
	Dec) echo 12;;
	esac
}

# compare two dates of the form "MMM YY HH:MM:SS YYYY" and
# return <0 if date1 < date2, 0 if date1 = date2, >0 if date1 > date2
datecmp() {
	eval `echo "$1" | sed 's/:/ /g' | awk '{printf "mon1=%s day1=%s hr1=%s min1=%s sec1=%s yr1=%s\n",$1,$2,$3,$4,$5,$6}'`
	eval `echo "$2" | sed 's/:/ /g' | awk '{printf "mon2=%s day2=%s hr2=%s min2=%s sec2=%s yr2=%s\n",$1,$2,$3,$4,$5,$6}'`
	diff=`expr $yr1 - $yr2`
	if [ $diff -ne 0 ]; then
		echo $diff
		return
	fi
	mm1=`monthnum $mon1`
	mm2=`monthnum $mon2`
	diff=`expr $mm1 - $mm2`
	if [ $diff -ne 0 ]; then
		echo $diff
		return
	fi
	diff=`expr $day1 - $day2`
	if [ $diff -ne 0 ]; then
		echo $diff
		return
	fi
	diff=`expr $hr1 - $hr2`
	if [ $diff -ne 0 ]; then
		echo $diff
		return
	fi
	diff=`expr $min1 - $min2`
	if [ $diff -ne 0 ]; then
		echo $diff
		return
	fi
	diff=`expr $sec1 - $sec2`
	echo $diff
	return
}

# translate a date of the form "MMM DD HH:MM:SS YYYY" into a
# form suitable for use with the at command.
atdate () {
	eval `echo $* | sed 's/:/ /g' | awk '{printf "mon=%s day=%s hr=%s min=%s sec=%s yr=%s\n",$1,$2,$3,$4,$5,$6}'`
	min=`expr $min - $LEADTIME`
	if [ $min -lt 0 ]; then
		echo "`basename $0`: too much lead time"
	fi
	echo "$hr:$min $mon $day"
}

# get seconds from a date of the form "MMM DD HH:MM:SS YYYY"
seconds() {
	expr "$*" : '.*:..:\(..\) .*'
}

# get DST change data
trap "rm -f $TMP; exit 1" 2 3
zdump -v $TIMEZONE >$TMP

# save the current date for comparison
set `head -1 $TMP`
NOW="$3 $4 $5 $6"
THISYEAR=$6

# look at the DST change data and find the next change
sed -e '1d' -e 's/isdst=//' -e 's/.*= ... //' $TMP | \
while read timeinfo; do
	set $timeinfo

	# speed things up by ignoring old years
	if [ $THISYEAR -gt $4 ]; then
		continue
	fi

	DATE="$1 $2 $3 $4"
	# if this DST change is in the future
	if [ `datecmp "$NOW" "$DATE"` -lt 0 ]; then
		# schedule at job to fix cron and start the cycle all over again
		at `atdate $DATE` <<!
			# sleep for the leadtime we specified to make sure
			# the DST change has occured.  Add seconds before change
			# and a fudge to make sure cron is through processing.
			sleep `expr $LEADTIME \* 60 + \`seconds $DATE\` + 10`
			echo Restarting cron due to DST change
			pid=\`ps ax | grep -w cron | grep -v grep | awk '{print \$1}'\`
			kill \$pid
			cron
			# Start the cycle over again
			echo Scheduling next cron restart
			$0
!
		break
	fi
done


# remove tmp file
rm -f $TMP
@//E*O*F dstcronfix//
chmod u=rwx,g=rx,o=rx dstcronfix
 
exit 0

Newsgroups: alt.sys.sun,comp.sys.sun.misc,comp.unix.sysv386,comp.sys.ibm.pc.misc