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 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;136 if (strncmp("TZif", (char*)tzdata, 4)!=0)137 goto errfree;139 if (parsehead()==-1) {140 errfree:141 free(tzdata);142 tzdata = nil;143 z.timecnt = 0;144 return;145 }146 }148 static149 tlong150 gett4(uchar *p)151 {152 long l;154 l = get4(p);155 if (l<0)156 return 0;157 return l;158 }159 int160 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 }171 int172 zonelookuptinfo(Tinfo *ti, tlong t)173 {174 uchar *p;175 int i;176 tlong oldtt, tt;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 }198 void199 zonedump(int fd)200 {201 int i;202 uchar *p;203 tlong t;204 Tinfo ti;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 }