13e12c5d1SDavid du Colombier #include <stdlib.h>
23e12c5d1SDavid du Colombier #include <sys/types.h>
33e12c5d1SDavid du Colombier #include <fcntl.h>
43e12c5d1SDavid du Colombier #include <time.h>
53e12c5d1SDavid du Colombier #include <ctype.h>
63e12c5d1SDavid du Colombier #include <string.h>
73e12c5d1SDavid du Colombier #include <unistd.h>
83e12c5d1SDavid du Colombier
93e12c5d1SDavid du Colombier #define TZFILE "/etc/TZ"
103e12c5d1SDavid du Colombier
113e12c5d1SDavid du Colombier static char TZ[128];
123e12c5d1SDavid du Colombier static char std[32] = "GMT0";
133e12c5d1SDavid du Colombier static char dst[32];
143e12c5d1SDavid du Colombier char *tzname[2] = {
153e12c5d1SDavid du Colombier std, dst
163e12c5d1SDavid du Colombier };
173e12c5d1SDavid du Colombier time_t tzoffset, tzdstoffset;
183e12c5d1SDavid du Colombier int tzdst = 0;
193e12c5d1SDavid du Colombier
203e12c5d1SDavid du Colombier static int
offset(char * env,time_t * off)213e12c5d1SDavid du Colombier offset(char *env, time_t *off)
223e12c5d1SDavid du Colombier {
233e12c5d1SDavid du Colombier int n, sign;
243e12c5d1SDavid du Colombier size_t len, retlen;
253e12c5d1SDavid du Colombier
263e12c5d1SDavid du Colombier retlen = 0;
273e12c5d1SDavid du Colombier sign = 1;
283e12c5d1SDavid du Colombier /*
293e12c5d1SDavid du Colombier * strictly, no sign is allowed in the 'time' part of the
303e12c5d1SDavid du Colombier * dst start/stop rules, but who cares?
313e12c5d1SDavid du Colombier */
323e12c5d1SDavid du Colombier if (*env == '-' || *env == '+') {
333e12c5d1SDavid du Colombier if (*env++ == '-')
343e12c5d1SDavid du Colombier sign = -1;
353e12c5d1SDavid du Colombier retlen++;
363e12c5d1SDavid du Colombier }
373e12c5d1SDavid du Colombier if ((len = strspn(env, ":0123456789")) == 0)
383e12c5d1SDavid du Colombier return 0;
393e12c5d1SDavid du Colombier retlen += len;
403e12c5d1SDavid du Colombier for (*off = 0; len && isdigit(*env); len--) /* hours */
413e12c5d1SDavid du Colombier *off = *off*10 + (*env++ - '0')*60*60;
423e12c5d1SDavid du Colombier if (len) {
433e12c5d1SDavid du Colombier if (*env++ != ':')
443e12c5d1SDavid du Colombier return 0;
453e12c5d1SDavid du Colombier len--;
463e12c5d1SDavid du Colombier }
473e12c5d1SDavid du Colombier for (n = 0; len && isdigit(*env); len--) /* minutes */
483e12c5d1SDavid du Colombier n = n*10 + (*env++ - '0')*60;
493e12c5d1SDavid du Colombier *off += n;
503e12c5d1SDavid du Colombier if (len) {
513e12c5d1SDavid du Colombier if (*env++ != ':')
523e12c5d1SDavid du Colombier return 0;
533e12c5d1SDavid du Colombier len--;
543e12c5d1SDavid du Colombier }
553e12c5d1SDavid du Colombier for (n = 0; len && isdigit(*env); len--) /* seconds */
563e12c5d1SDavid du Colombier n = n*10 + (*env++ - '0');
573e12c5d1SDavid du Colombier *off = (*off + n)*sign;
583e12c5d1SDavid du Colombier return retlen;
593e12c5d1SDavid du Colombier }
603e12c5d1SDavid du Colombier
613e12c5d1SDavid du Colombier /*
623e12c5d1SDavid du Colombier * TZ=stdoffset[dst[offset][,start[/time],end[/time]]]
633e12c5d1SDavid du Colombier */
643e12c5d1SDavid du Colombier void
tzset(void)653e12c5d1SDavid du Colombier tzset(void)
663e12c5d1SDavid du Colombier {
673e12c5d1SDavid du Colombier char *env, *p, envbuf[128];
683e12c5d1SDavid du Colombier int fd, i;
693e12c5d1SDavid du Colombier size_t len, retlen;
703e12c5d1SDavid du Colombier time_t off;
713e12c5d1SDavid du Colombier
723e12c5d1SDavid du Colombier /*
733e12c5d1SDavid du Colombier * get the TZ environment variable and check for validity.
743e12c5d1SDavid du Colombier * the implementation-defined manner for dealing with the
753e12c5d1SDavid du Colombier * leading ':' format is to reject it.
763e12c5d1SDavid du Colombier * if it's ok, stash a copy away for quick comparison next time.
773e12c5d1SDavid du Colombier */
783e12c5d1SDavid du Colombier if ((env = getenv("TZ")) == 0) {
793e12c5d1SDavid du Colombier if ((fd = open(TZFILE, O_RDONLY)) == -1)
803e12c5d1SDavid du Colombier return;
813e12c5d1SDavid du Colombier if (read(fd, envbuf, sizeof(envbuf)-1) == -1) {
823e12c5d1SDavid du Colombier close(fd);
833e12c5d1SDavid du Colombier return;
843e12c5d1SDavid du Colombier }
853e12c5d1SDavid du Colombier close(fd);
863e12c5d1SDavid du Colombier for (i = 0; i < sizeof(envbuf); i++) {
873e12c5d1SDavid du Colombier if (envbuf[i] != '\n')
883e12c5d1SDavid du Colombier continue;
893e12c5d1SDavid du Colombier envbuf[i] = '\0';
903e12c5d1SDavid du Colombier break;
913e12c5d1SDavid du Colombier }
923e12c5d1SDavid du Colombier env = envbuf;
933e12c5d1SDavid du Colombier }
943e12c5d1SDavid du Colombier if (strcmp(env, TZ) == 0)
953e12c5d1SDavid du Colombier return;
963e12c5d1SDavid du Colombier if (*env == 0 || *env == ':')
973e12c5d1SDavid du Colombier return;
983e12c5d1SDavid du Colombier strncpy(TZ, env, sizeof(TZ)-1);
993e12c5d1SDavid du Colombier TZ[sizeof(TZ)-1] = 0;
1003e12c5d1SDavid du Colombier /*
1013e12c5d1SDavid du Colombier * get the 'std' string.
1023e12c5d1SDavid du Colombier * before committing, check there is a valid offset.
1033e12c5d1SDavid du Colombier */
1043e12c5d1SDavid du Colombier if ((len = strcspn(env, ":0123456789,-+")) == 0)
1053e12c5d1SDavid du Colombier return;
1063e12c5d1SDavid du Colombier if ((retlen = offset(env+len, &off)) == 0)
1073e12c5d1SDavid du Colombier return;
1083e12c5d1SDavid du Colombier for (p = std, i = len+retlen; i; i--)
1093e12c5d1SDavid du Colombier *p++ = *env++;
1103e12c5d1SDavid du Colombier *p = 0;
1113e12c5d1SDavid du Colombier tzoffset = -off;
1123e12c5d1SDavid du Colombier /*
1133e12c5d1SDavid du Colombier * get the 'dst' string (if any).
1143e12c5d1SDavid du Colombier */
1153e12c5d1SDavid du Colombier if (*env == 0 || (len = strcspn(env, ":0123456789,-+")) == 0)
1163e12c5d1SDavid du Colombier return;
1173e12c5d1SDavid du Colombier for (p = dst; len; len--)
1183e12c5d1SDavid du Colombier *p++ = *env++;
1193e12c5d1SDavid du Colombier *p = 0;
1203e12c5d1SDavid du Colombier /*
1213e12c5d1SDavid du Colombier * optional dst offset.
1223e12c5d1SDavid du Colombier * default is one hour.
1233e12c5d1SDavid du Colombier */
1243e12c5d1SDavid du Colombier tzdst = 1;
1253e12c5d1SDavid du Colombier if (retlen = offset(env+len, &off)) {
1263e12c5d1SDavid du Colombier tzdstoffset = -off;
1273e12c5d1SDavid du Colombier env += retlen;
1283e12c5d1SDavid du Colombier }
1293e12c5d1SDavid du Colombier else
1303e12c5d1SDavid du Colombier tzdstoffset = tzoffset + 60*60;
1313e12c5d1SDavid du Colombier /*
1323e12c5d1SDavid du Colombier * optional rule(s) for start/end of dst.
1333e12c5d1SDavid du Colombier */
1343e12c5d1SDavid du Colombier if (*env == 0 || *env != ',' || *(env+1) == 0)
1353e12c5d1SDavid du Colombier return;
1363e12c5d1SDavid du Colombier env++;
1373e12c5d1SDavid du Colombier /*
1383e12c5d1SDavid du Colombier * we could go on...
1393e12c5d1SDavid du Colombier * but why bother?
1403e12c5d1SDavid du Colombier */
141*781103c4SDavid du Colombier USED(env);
1423e12c5d1SDavid du Colombier }
143