Index: contrib/tzcode/stdtime/localtime.c =================================================================== --- contrib/tzcode/stdtime/localtime.c +++ contrib/tzcode/stdtime/localtime.c @@ -170,6 +170,7 @@ ** Prototypes for static functions. */ +static int check_tz_change(int is_lcl_set); static long detzcode(const char * codep); static time_t detzcode64(const char * codep); static int differ_by_repeat(time_t t1, time_t t0); @@ -235,8 +236,16 @@ #define TZ_STRLEN_MAX 255 #endif /* !defined TZ_STRLEN_MAX */ +#define TZ_FILENAME "/etc/localtime" +#define MAX_CHECK_COUNT 10 +#define CHECK_INTERVAL 10 static char lcl_TZname[TZ_STRLEN_MAX + 1]; static int lcl_is_set; +static int done_env_read = 0; +static int watch_changes = 1; /* Always starts off taking notice */ +static time_t tzfile_ctime = (time_t)0; /* will always want the first check */ +static time_t last_check_time = (time_t)0; /* It's time to check immediately */ +static int check_times; static pthread_once_t gmt_once = PTHREAD_ONCE_INIT; static pthread_rwlock_t lcl_rwlock = PTHREAD_RWLOCK_INITIALIZER; static pthread_once_t gmtime_once = PTHREAD_ONCE_INIT; @@ -270,6 +279,63 @@ time_t altzone = 0; #endif /* defined ALTZONE */ +static int +check_tz_change(int is_lcl_set) +{ + int is_change = 0; + if ( watch_changes ) { + struct stat buf; + time_t current_time = time(NULL); + + if ( ! done_env_read ) { + char *env_ptr; + + env_ptr = getenv("ZONEINFO_WATCH_CHANGES"); + done_env_read = 1; + if (env_ptr == NULL) { + watch_changes = 1; /* default value */ + } else { + if (strncmp("yes", env_ptr, 3)) { + watch_changes = 0; + } else { + watch_changes = 1; + } + } + } + + if (check_times++ % MAX_CHECK_COUNT == 0 || + (current_time - last_check_time > CHECK_INTERVAL)) { + if (fstatat(AT_FDCWD, TZ_FILENAME, &buf, AT_SYMLINK_NOFOLLOW ) == 0) { + if (tzfile_ctime != buf.st_ctime) { + tzfile_ctime = buf.st_ctime; + is_change = 1; + } + } else { + if (tzfile_ctime != 0) { + /* it went away.. do whatever we do with no TZ */ + is_change = 1; + tzfile_ctime = (time_t)0; + } + } + check_times = 0; + last_check_time = current_time; + } + } + + if (is_lcl_set == 0 && is_change == 0) { + if ( lcl_is_set >= 0 ) { + is_change = 1; + } + } else if (is_lcl_set == 1 && is_change == 0) { + if ( lcl_is_set <= 0) { + is_change = 1; + } + } + + return is_change; +} + + static long detzcode(const char *const codep) { @@ -1226,7 +1292,7 @@ { if (!rdlocked) _RWLOCK_RDLOCK(&lcl_rwlock); - if (lcl_is_set < 0) { + if ((check_tz_change(0) == 0)) { if (!rdlocked) _RWLOCK_UNLOCK(&lcl_rwlock); return; @@ -1276,7 +1342,7 @@ if (!rdlocked) _RWLOCK_RDLOCK(&lcl_rwlock); - if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) { + if (strcmp(lcl_TZname, name) == 0 && check_tz_change(1) == 0 ) { if (!rdlocked) _RWLOCK_UNLOCK(&lcl_rwlock); return;