Package: cron Version: 3.0pl1-100 Severity: normal Jobs scheduled to run between 1 and 2 am are not run when time moves forward for 1-3 hours (at the beginning of DST) and are run twice when time moves backward for 1-3 hours (at the end of DST).
Included is the patch against current trunk. *** pkg-cron-trunk-dst.diff Index: cron.c =================================================================== --- cron.c (revision 413) +++ cron.c (working copy) @@ -37,7 +37,7 @@ static void usage __P((void)), run_reboot_jobs __P((cron_db *)), find_jobs __P((time_min, cron_db *, int, int)), - set_time __P((void)), + set_time __P((int)), cron_sleep __P((time_min)), #ifdef USE_SIGCHLD sigchld_handler __P((int)), @@ -152,7 +152,7 @@ #endif load_database(&database); - set_time(); + set_time(TRUE); run_reboot_jobs(&database); timeRunning = virtualTime = clockTime; @@ -173,7 +173,7 @@ /* ... wait for the time (in minutes) to change ... */ do { cron_sleep(timeRunning + 1); - set_time(); + set_time(FALSE); } while (clockTime == timeRunning); timeRunning = clockTime; @@ -186,6 +186,9 @@ */ timeDiff = timeRunning - virtualTime; + Debug(DSCH, ("[%d] pulse: %d = %d - %d\n", + getpid(), timeDiff, timeRunning, virtualTime)); + /* shortcut for the most common case */ if (timeDiff == 1) { virtualTime = timeRunning; @@ -239,7 +242,7 @@ sleep(10); virtualTime++; find_jobs(virtualTime, &database, FALSE, TRUE); - set_time(); + set_time(FALSE); } while (virtualTime< timeRunning && clockTime == timeRunning); break; @@ -326,7 +329,7 @@ int doNonWild; { time_t virtualSecond = vtime * SECONDS_PER_MINUTE; - register struct tm *tm = localtime(&virtualSecond); + register struct tm *tm = gmtime(&virtualSecond); register int minute, hour, dom, month, dow; register user *u; register entry *e; @@ -375,10 +378,22 @@ * note that clockTime is a unix wallclock time converted to minutes */ static void -set_time() +set_time(int initialize) { - StartTime = time((time_t *)0); - clockTime = StartTime / (unsigned long)SECONDS_PER_MINUTE; + struct tm tm; + static int isdst; + + StartTime = time(NULL); + + /* We adjust the time to GMT so we can catch DST changes. */ + tm = *localtime(&StartTime); + if (initialize || tm.tm_isdst != isdst) { + isdst = tm.tm_isdst; + GMToff = get_gmtoff(&StartTime, &tm); + Debug(DSCH, ("[%ld] GMToff=%ld\n", + (long)getpid(), (long)GMToff)) + } + clockTime = (StartTime + GMToff) / (time_t)SECONDS_PER_MINUTE; } /* @@ -390,12 +405,19 @@ { register int seconds_to_wait; - seconds_to_wait = (int)(target*SECONDS_PER_MINUTE - time((time_t*)0)) + 1; + time_t t1, t2; + t1 = time(NULL) + GMToff; + + seconds_to_wait = (int)(target * SECONDS_PER_MINUTE - t1) + 1; Debug(DSCH, ("[%d] TargetTime=%ld, sec-to-wait=%d\n", getpid(), (long)target*SECONDS_PER_MINUTE, seconds_to_wait)) - if (seconds_to_wait > 0 && seconds_to_wait< 65) + while (seconds_to_wait > 0 && seconds_to_wait< 65) { sleep((unsigned int) seconds_to_wait); + t2 = time(NULL) + GMToff; + seconds_to_wait -= (int)(t2 - t1); + t1 = t2; + } } Index: cron.h =================================================================== --- cron.h (revision 413) +++ cron.h (working copy) @@ -279,6 +279,7 @@ time_min timeRunning; time_min virtualTime; time_min clockTime; +static long GMToff; int stay_foreground; int lsbsysinit_mode; Index: misc.c =================================================================== --- misc.c (revision 413) +++ misc.c (working copy) @@ -718,3 +718,38 @@ } int swap_uids_back() { return swap_uids(); } #endif /*HAVE_SAVED_UIDS*/ + + +/* Return the offset from GMT in seconds (algorithm taken from sendmail). + * + * warning: + * clobbers the static storage space used by localtime() and gmtime(). + * If the local pointer is non-NULL it *must* point to a local copy. + */ +#ifndef HAVE_TM_GMTOFF +long get_gmtoff(time_t *clock, struct tm *local) +{ + struct tm gmt; + long offset; + + gmt = *gmtime(clock); + if (local == NULL) + local = localtime(clock); + + offset = (local->tm_sec - gmt.tm_sec) + + ((local->tm_min - gmt.tm_min) * 60) + + ((local->tm_hour - gmt.tm_hour) * 3600); + + /* Timezone may cause year rollover to happen on a different day. */ + if (local->tm_year < gmt.tm_year) + offset -= 24 * 3600; + else if (local->tm_year > gmt.tm_year) + offset -= 24 * 3600; + else if (local->tm_yday < gmt.tm_yday) + offset -= 24 * 3600; + else if (local->tm_yday > gmt.tm_yday) + offset += 24 * 3600; + + return (offset); +} +#endif /* HAVE_TM_GMTOFF */ -- System Information: Debian Release: 4.0 APT prefers stable APT policy: (500, 'stable') Architecture: amd64 (x86_64) Shell: /bin/sh linked to /bin/bash Kernel: Linux 2.6.22-4-amd64 Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) Versions of packages cron depends on: ii adduser 3.102 Add and remove users and groups ii debianutils 2.17 Miscellaneous utilities specific t ii libc6 2.3.6.ds1-13etch5 GNU C Library: Shared libraries ii libpam0g 0.79-5 Pluggable Authentication Modules l ii libselinux1 1.32-3 SELinux shared libraries ii lsb-base 3.1-23.2etch1 Linux Standard Base 3.1 init scrip Versions of packages cron recommends: ii postfix [mail-transport-agent 2.3.8-2 A high-performance mail transport -- no debconf information -- To UNSUBSCRIBE, email to [EMAIL PROTECTED] with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]