Blob
1 #include <u.h>2 #include <libc.h>4 /*5 * Access local time entries of zoneinfo files.6 * Formats 0 and 2 are supported, and 4-byte timestamps7 *8 * Copyright © 2008 M. Teichgräber9 * Contributed under the terms of the Lucent Public License 1.02.10 */11 #include "zoneinfo.h"13 static14 struct Zoneinfo15 {16 int timecnt; /* # of transition times */17 int typecnt; /* # of local time types */18 int charcnt; /* # of characters of time zone abbreviation strings */20 uchar *ptime;21 uchar *ptype;22 uchar *ptt;23 uchar *pzone;24 } z;26 static uchar *tzdata;28 static29 uchar*30 readtzfile(char *file)31 {32 uchar *p;33 int fd;34 Dir *d;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 void51 tzfile(char *f)52 {53 if (tzdata!=nil) {54 free(tzdata);55 tzdata = nil;56 }57 z.timecnt = 0;58 zonefile = f;59 }61 static62 long63 get4(uchar *p)64 {65 return (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3];66 }68 enum {69 TTinfosz = 4+1+1,70 };72 static73 int74 parsehead(void)75 {76 uchar *p;77 int ver;79 ver = tzdata[4];80 if (ver!=0)81 if (ver!='2')82 return -1;84 p = tzdata + 4 + 1 + 15;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 }98 static99 void100 ttinfo(Tinfo *ti, int tti)101 {102 uchar *p;103 int i;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 }114 static115 void116 readtimezone(void)117 {118 char *tmp;120 z.timecnt = 0;121 if(zonefile==nil) {122 if ((tmp=getenv("timezone"))!=nil) {123 tzdata = readtzfile(tmp);124 free(tmp);125 goto havedata;126 }127 zonefile = "/etc/localtime";128 }129 tzdata = readtzfile(zonefile);130 if (tzdata==nil)131 return;133 havedata:134 if (strncmp("TZif", (char*)tzdata, 4)!=0)135 goto errfree;137 if (parsehead()==-1) {138 errfree:139 free(tzdata);140 tzdata = nil;141 z.timecnt = 0;142 return;143 }144 }146 static147 tlong148 gett4(uchar *p)149 {150 long l;152 l = get4(p);153 if (l<0)154 return 0;155 return l;156 }157 int158 zonetinfo(Tinfo *ti, int i)159 {160 if (tzdata==nil)161 readtimezone();162 if (i<0 || i>=z.timecnt)163 return -1;164 ti->t = gett4(z.ptime + 4*i);165 ttinfo(ti, i);166 return i;167 }169 int170 zonelookuptinfo(Tinfo *ti, tlong t)171 {172 uchar *p;173 int i;174 tlong oldtt, tt;176 if (tzdata==nil)177 readtimezone();178 oldtt = 0;179 p = z.ptime;180 for (i=0; i<z.timecnt; i++) {181 tt = gett4(p);182 if (t<tt)183 break;184 oldtt = tt;185 p += 4;186 }187 if (i>0) {188 ttinfo(ti, i-1);189 ti->t = oldtt;190 // fprint(2, "t:%ld off:%d dflag:%d %s\n", (long)ti->t, ti->tzoff, ti->dlflag, ti->zone);191 return i-1;192 }193 return -1;194 }196 void197 zonedump(int fd)198 {199 int i;200 uchar *p;201 tlong t;202 Tinfo ti;204 if (tzdata==nil)205 readtimezone();206 p = z.ptime;207 for (i=0; i<z.timecnt; i++) {208 t = gett4(p);209 ttinfo(&ti, i);210 fprint(fd, "%ld\t%d\t%d\t%s\n", (long)t, ti.tzoff, ti.dlflag, ti.zone);211 p += 4;212 }213 }