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 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 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 } 142