use default timezone from /etc/localtime if $TZ is unset/blank
[musl] / src / time / __tz.c
index 81676d3..92c43a5 100644 (file)
@@ -121,14 +121,14 @@ int __munmap(void *, size_t);
 static void do_tzset()
 {
        char buf[NAME_MAX+25], *pathname=buf+24;
-       const char *try, *s;
+       const char *try, *s, *p;
        const unsigned char *map = 0;
        size_t i;
        static const char search[] =
                "/usr/share/zoneinfo/\0/share/zoneinfo/\0/etc/zoneinfo/\0";
 
        s = getenv("TZ");
-       if (!s || !*s) s = __gmt;
+       if (!s || !*s) s = "/etc/localtime";
 
        if (old_tz && !strcmp(s, old_tz)) return;
 
@@ -138,7 +138,7 @@ static void do_tzset()
         * free so as not to pull it into static programs. Growth
         * strategy makes it so free would have minimal benefit anyway. */
        i = strlen(s);
-       if (i > PATH_MAX+1) s = "", i = 0;
+       if (i > PATH_MAX+1) s = __gmt, i = 3;
        if (i >= old_tz_size) {
                old_tz_size *= 2;
                if (i >= old_tz_size) old_tz_size = i+1;
@@ -147,37 +147,40 @@ static void do_tzset()
        }
        if (old_tz) memcpy(old_tz, s, i+1);
 
-       if (*s == ':') s++;
-
        /* Non-suid can use an absolute tzfile pathname or a relative
         * pathame beginning with "."; in secure mode, only the
         * standard path will be searched. */
-       if (*s == '/' || *s == '.') {
-               if (!libc.secure) map = __map_file(s, &map_size);
-       } else {
-               for (i=0; s[i] && s[i]!=','; i++) {
-                       if (s[i]=='/') {
-                               size_t l = strlen(s);
-                               if (l > NAME_MAX || strchr(s, '.'))
-                                       break;
+       if (*s == ':' || ((p=strchr(s, '/')) && !memchr(s, ',', p-s))) {
+               if (*s == ':') s++;
+               if (*s == '/' || *s == '.') {
+                       if (!libc.secure || !strcmp(s, "/etc/localtime"))
+                               map = __map_file(s, &map_size);
+               } else {
+                       size_t l = strlen(s);
+                       if (l <= NAME_MAX && !strchr(s, '.')) {
                                memcpy(pathname, s, l+1);
                                pathname[l] = 0;
-                               for (try=search; !map && *try; try+=l) {
+                               for (try=search; !map && *try; try+=l+1) {
                                        l = strlen(try);
                                        memcpy(pathname-l, try, l);
                                        map = __map_file(pathname-l, &map_size);
                                }
-                               break;
                        }
                }
+               if (!map) s = __gmt;
+       }
+       if (map && (map_size < 44 || memcmp(map, "TZif", 4))) {
+               __munmap((void *)map, map_size);
+               map = 0;
+               s = __gmt;
        }
 
        zi = map;
        if (map) {
                int scale = 2;
                if (sizeof(time_t) > 4 && map[4]=='2') {
-                       size_t skip = zi_dotprod(zi, VEC(1,1,8,5,6,1), 6);
-                       trans = zi+skip+44+20;
+                       size_t skip = zi_dotprod(zi+20, VEC(1,1,8,5,6,1), 6);
+                       trans = zi+skip+44+44;
                        scale++;
                } else {
                        trans = zi+44;