xref: /plan9/sys/src/ape/lib/ap/posix/tzset.c (revision 781103c4074deb8af160e8a0da2742ba6b29dc2b)
1 #include <stdlib.h>
2 #include <sys/types.h>
3 #include <fcntl.h>
4 #include <time.h>
5 #include <ctype.h>
6 #include <string.h>
7 #include <unistd.h>
8 
9 #define TZFILE	"/etc/TZ"
10 
11 static char TZ[128];
12 static char std[32] = "GMT0";
13 static char dst[32];
14 char *tzname[2] = {
15 	std, dst
16 };
17 time_t tzoffset, tzdstoffset;
18 int tzdst = 0;
19 
20 static int
offset(char * env,time_t * off)21 offset(char *env, time_t *off)
22 {
23 	int n, sign;
24 	size_t len, retlen;
25 
26 	retlen = 0;
27 	sign = 1;
28 	/*
29 	 * strictly, no sign is allowed in the 'time' part of the
30 	 * dst start/stop rules, but who cares?
31 	 */
32 	if (*env == '-' || *env == '+') {
33 		if (*env++ == '-')
34 			sign = -1;
35 		retlen++;
36 	}
37 	if ((len = strspn(env, ":0123456789")) == 0)
38 		return 0;
39 	retlen += len;
40 	for (*off = 0; len && isdigit(*env); len--)		/* hours */
41 		*off = *off*10 + (*env++ - '0')*60*60;
42 	if (len) {
43 		if (*env++ != ':')
44 			return 0;
45 		len--;
46 	}
47 	for (n = 0; len && isdigit(*env); len--)		/* minutes */
48 		n = n*10 + (*env++ - '0')*60;
49 	*off += n;
50 	if (len) {
51 		if (*env++ != ':')
52 			return 0;
53 		len--;
54 	}
55 	for (n = 0; len && isdigit(*env); len--)		/* seconds */
56 		n = n*10 + (*env++ - '0');
57 	*off = (*off + n)*sign;
58 	return retlen;
59 }
60 
61 /*
62  * TZ=stdoffset[dst[offset][,start[/time],end[/time]]]
63  */
64 void
tzset(void)65 tzset(void)
66 {
67 	char *env, *p, envbuf[128];
68 	int fd, i;
69 	size_t len, retlen;
70 	time_t off;
71 
72 	/*
73 	 * get the TZ environment variable and check for validity.
74 	 * the implementation-defined manner for dealing with the
75 	 * leading ':' format is to reject it.
76 	 * if it's ok, stash a copy away for quick comparison next time.
77 	 */
78 	if ((env = getenv("TZ")) == 0) {
79 		if ((fd = open(TZFILE, O_RDONLY)) == -1)
80 			return;
81 		if (read(fd, envbuf, sizeof(envbuf)-1) == -1) {
82 			close(fd);
83 			return;
84 		}
85 		close(fd);
86 		for (i = 0; i < sizeof(envbuf); i++) {
87 			if (envbuf[i] != '\n')
88 				continue;
89 			envbuf[i] = '\0';
90 			break;
91 		}
92 		env = envbuf;
93 	}
94 	if (strcmp(env, TZ) == 0)
95 		return;
96 	if (*env == 0 || *env == ':')
97 		return;
98 	strncpy(TZ, env, sizeof(TZ)-1);
99 	TZ[sizeof(TZ)-1] = 0;
100 	/*
101 	 * get the 'std' string.
102 	 * before committing, check there is a valid offset.
103 	 */
104 	if ((len = strcspn(env, ":0123456789,-+")) == 0)
105 		return;
106 	if ((retlen = offset(env+len, &off)) == 0)
107 		return;
108 	for (p = std, i = len+retlen; i; i--)
109 		*p++ = *env++;
110 	*p = 0;
111 	tzoffset = -off;
112 	/*
113 	 * get the 'dst' string (if any).
114 	 */
115 	if (*env == 0 || (len = strcspn(env, ":0123456789,-+")) == 0)
116 		return;
117 	for (p = dst; len; len--)
118 		*p++ = *env++;
119 	*p = 0;
120 	/*
121 	 * optional dst offset.
122 	 * default is one hour.
123 	 */
124 	tzdst = 1;
125 	if (retlen = offset(env+len, &off)) {
126 		tzdstoffset = -off;
127 		env += retlen;
128 	}
129 	else
130 		tzdstoffset = tzoffset + 60*60;
131 	/*
132 	 * optional rule(s) for start/end of dst.
133 	 */
134 	if (*env == 0 || *env != ',' || *(env+1) == 0)
135 		return;
136 	env++;
137 	/*
138 	 * we could go on...
139 	 * but why bother?
140 	 */
141 	USED(env);
142 }
143