zoneinfo.c (3092B)
1 #include <u.h> 2 #include <libc.h> 3 4 /* 5 * Access local time entries of zoneinfo files. 6 * Formats 0 and 2 are supported, and 4-byte timestamps 7 * 8 * Copyright © 2008 M. Teichgräber 9 * Contributed under the terms of the Lucent Public License 1.02. 10 */ 11 #include "zoneinfo.h" 12 13 static 14 struct Zoneinfo 15 { 16 int timecnt; /* # of transition times */ 17 int typecnt; /* # of local time types */ 18 int charcnt; /* # of characters of time zone abbreviation strings */ 19 20 uchar *ptime; 21 uchar *ptype; 22 uchar *ptt; 23 uchar *pzone; 24 } z; 25 26 static uchar *tzdata; 27 28 static 29 uchar* 30 readtzfile(char *file) 31 { 32 uchar *p; 33 int fd; 34 Dir *d; 35 36 fd = open(file, OREAD); 37 if (fd<0) 38 return nil; 39 d = dirfstat(fd); 40 if (d==nil) 41 return nil; 42 p = malloc(d->length); 43 if (p!=nil) 44 readn(fd, p, d->length); 45 free(d); 46 close(fd); 47 return p; 48 } 49 static char *zonefile; 50 void 51 tzfile(char *f) 52 { 53 if (tzdata!=nil) { 54 free(tzdata); 55 tzdata = nil; 56 } 57 z.timecnt = 0; 58 zonefile = f; 59 } 60 61 static 62 long 63 get4(uchar *p) 64 { 65 return (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]; 66 } 67 68 enum { 69 TTinfosz = 4+1+1, 70 }; 71 72 static 73 int 74 parsehead(void) 75 { 76 uchar *p; 77 int ver; 78 79 ver = tzdata[4]; 80 if (ver!=0) 81 if (ver!='2') 82 return -1; 83 84 p = tzdata + 4 + 1 + 15; 85 86 z.timecnt = get4(p+3*4); 87 z.typecnt = get4(p+4*4); 88 if (z.typecnt==0) 89 return -1; 90 z.charcnt = get4(p+5*4); 91 z.ptime = p+6*4; 92 z.ptype = z.ptime + z.timecnt*4; 93 z.ptt = z.ptype + z.timecnt; 94 z.pzone = z.ptt + z.typecnt*TTinfosz; 95 return 0; 96 } 97 98 static 99 void 100 ttinfo(Tinfo *ti, int tti) 101 { 102 uchar *p; 103 int i; 104 105 i = z.ptype[tti]; 106 assert(i<z.typecnt); 107 p = z.ptt + i*TTinfosz; 108 ti->tzoff = get4(p); 109 ti->dlflag = p[4]; 110 assert(p[5]<z.charcnt); 111 ti->zone = (char*)z.pzone + p[5]; 112 } 113 114 static 115 void 116 readtimezone(void) 117 { 118 char *tmp; 119 120 z.timecnt = 0; 121 switch (zonefile==nil) { 122 default: 123 if ((tmp=getenv("timezone"))!=nil) { 124 tzdata = readtzfile(tmp); 125 free(tmp); 126 break; 127 } 128 zonefile = "/etc/localtime"; 129 /* fall through */ 130 case 0: 131 tzdata = readtzfile(zonefile); 132 } 133 if (tzdata==nil) 134 return; 135 136 if (strncmp("TZif", (char*)tzdata, 4)!=0) 137 goto errfree; 138 139 if (parsehead()==-1) { 140 errfree: 141 free(tzdata); 142 tzdata = nil; 143 z.timecnt = 0; 144 return; 145 } 146 } 147 148 static 149 tlong 150 gett4(uchar *p) 151 { 152 long l; 153 154 l = get4(p); 155 if (l<0) 156 return 0; 157 return l; 158 } 159 int 160 zonetinfo(Tinfo *ti, int i) 161 { 162 if (tzdata==nil) 163 readtimezone(); 164 if (i<0 || i>=z.timecnt) 165 return -1; 166 ti->t = gett4(z.ptime + 4*i); 167 ttinfo(ti, i); 168 return i; 169 } 170 171 int 172 zonelookuptinfo(Tinfo *ti, tlong t) 173 { 174 uchar *p; 175 int i; 176 tlong oldtt, tt; 177 178 if (tzdata==nil) 179 readtimezone(); 180 oldtt = 0; 181 p = z.ptime; 182 for (i=0; i<z.timecnt; i++) { 183 tt = gett4(p); 184 if (t<tt) 185 break; 186 oldtt = tt; 187 p += 4; 188 } 189 if (i>0) { 190 ttinfo(ti, i-1); 191 ti->t = oldtt; 192 // fprint(2, "t:%ld off:%d dflag:%d %s\n", (long)ti->t, ti->tzoff, ti->dlflag, ti->zone); 193 return i-1; 194 } 195 return -1; 196 } 197 198 void 199 zonedump(int fd) 200 { 201 int i; 202 uchar *p; 203 tlong t; 204 Tinfo ti; 205 206 if (tzdata==nil) 207 readtimezone(); 208 p = z.ptime; 209 for (i=0; i<z.timecnt; i++) { 210 t = gett4(p); 211 ttinfo(&ti, i); 212 fprint(fd, "%ld\t%d\t%d\t%s\n", (long)t, ti.tzoff, ti.dlflag, ti.zone); 213 p += 4; 214 } 215 }