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