|  | --- a/src/time/__tz.c | 
|  | +++ b/src/time/__tz.c | 
|  | @@ -5,6 +5,10 @@ | 
|  | #include <string.h> | 
|  | #include <sys/mman.h> | 
|  | #include <ctype.h> | 
|  | +#include <unistd.h> | 
|  | +#include <sys/types.h> | 
|  | +#include <sys/stat.h> | 
|  | +#include <fcntl.h> | 
|  | #include "libc.h" | 
|  | #include "lock.h" | 
|  | #include "fork_impl.h" | 
|  | @@ -123,6 +127,67 @@ static size_t zi_dotprod(const unsigned | 
|  | return y; | 
|  | } | 
|  |  | 
|  | +#define TZ_BUFLEN		(2*TZNAME_MAX + 56) | 
|  | +static char *read_TZ_file(char *buf) | 
|  | +{ | 
|  | +	int r; | 
|  | +	int fd; | 
|  | +	char *p = NULL; | 
|  | + | 
|  | +	fd = open("/etc/TZ", O_RDONLY); | 
|  | +	if (fd >= 0) { | 
|  | +		/* Shorter, and does one fewer read syscall */ | 
|  | +		r = read(fd, buf, TZ_BUFLEN); | 
|  | +		if (r < 0) | 
|  | +			goto ERROR; | 
|  | +		p = buf + r; | 
|  | + | 
|  | +		if ((p > buf) && (p[-1] == '\n')) { /* Must end with newline */ | 
|  | +			p[-1] = 0; | 
|  | +			p = buf; | 
|  | +		} else { | 
|  | +ERROR: | 
|  | +			p = NULL; | 
|  | +		} | 
|  | +		close(fd); | 
|  | +	} else { | 
|  | +		fd = open("/etc/localtime", O_RDONLY); | 
|  | +		if (fd >= 0) { | 
|  | +			r = read(fd, buf, TZ_BUFLEN); | 
|  | +			if (r != TZ_BUFLEN | 
|  | +			 || strncmp(buf, "TZif", 4) != 0 | 
|  | +			 || (unsigned char)buf[4] < 2 | 
|  | +			 || lseek(fd, -TZ_BUFLEN, SEEK_END) < 0 | 
|  | +			) { | 
|  | +				goto ERROR; | 
|  | +			} | 
|  | +			/* tzfile.h from tzcode database says about TZif2+ files: | 
|  | +			** | 
|  | +			** If tzh_version is '2' or greater, the above is followed by a second instance | 
|  | +			** of tzhead and a second instance of the data in which each coded transition | 
|  | +			** time uses 8 rather than 4 chars, | 
|  | +			** then a POSIX-TZ-environment-variable-style string for use in handling | 
|  | +			** instants after the last transition time stored in the file | 
|  | +			** (with nothing between the newlines if there is no POSIX representation for | 
|  | +			** such instants). | 
|  | +			*/ | 
|  | +			r = read(fd, buf, TZ_BUFLEN); | 
|  | +			if (r <= 0 || buf[--r] != '\n') | 
|  | +				goto ERROR; | 
|  | +			buf[r] = 0; | 
|  | +			while (r != 0) { | 
|  | +				if (buf[--r] == '\n') { | 
|  | +					p = buf + r + 1; | 
|  | +					break; | 
|  | +				} | 
|  | +			} /* else ('\n' not found): p remains NULL */ | 
|  | +			close(fd); | 
|  | +		} | 
|  | +	} | 
|  | + | 
|  | +	return p; | 
|  | +} | 
|  | + | 
|  | static void do_tzset() | 
|  | { | 
|  | char buf[NAME_MAX+25], *pathname=buf+24; | 
|  | @@ -131,8 +196,15 @@ static void do_tzset() | 
|  | size_t i; | 
|  | static const char search[] = | 
|  | "/usr/share/zoneinfo/\0/share/zoneinfo/\0/etc/zoneinfo/\0"; | 
|  | +	char tzbuf[TZ_BUFLEN]; | 
|  |  | 
|  | s = getenv("TZ"); | 
|  | + | 
|  | +	/* if TZ is empty try to read it from /etc/TZ */ | 
|  | +	if (!s || !*s) { | 
|  | +		s = read_TZ_file(tzbuf); | 
|  | +	} | 
|  | + | 
|  | if (!s) s = "/etc/localtime"; | 
|  | if (!*s) s = __utc; | 
|  |  |