getservbyport_r: fix wrong result if getnameinfo fails with EAI_OVERFLOW
[musl] / src / time / __tz.c
index 1dbb0b8..c34b3eb 100644 (file)
@@ -3,7 +3,16 @@
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/mman.h>
+#include <ctype.h>
 #include "libc.h"
+#include "lock.h"
+#include "fork_impl.h"
+
+#define malloc __libc_malloc
+#define calloc undef
+#define realloc undef
+#define free undef
 
 long  __timezone = 0;
 int   __daylight = 0;
@@ -28,6 +37,7 @@ static char *old_tz = old_tz_buf;
 static size_t old_tz_size = sizeof old_tz_buf;
 
 static volatile int lock[1];
+volatile int *const __timezone_lockptr = lock;
 
 static int getint(const char **p)
 {
@@ -84,15 +94,15 @@ static void getname(char *d, const char **p)
        int i;
        if (**p == '<') {
                ++*p;
-               for (i=0; (*p)[i]!='>' && i<TZNAME_MAX; i++)
-                       d[i] = (*p)[i];
-               ++*p;
+               for (i=0; (*p)[i] && (*p)[i]!='>'; i++)
+                       if (i<TZNAME_MAX) d[i] = (*p)[i];
+               if ((*p)[i]) ++*p;
        } else {
-               for (i=0; ((*p)[i]|32)-'a'<26U && i<TZNAME_MAX; i++)
-                       d[i] = (*p)[i];
+               for (i=0; ((*p)[i]|32)-'a'<26U; i++)
+                       if (i<TZNAME_MAX) d[i] = (*p)[i];
        }
        *p += i;
-       d[i] = 0;
+       d[i<TZNAME_MAX?i:TZNAME_MAX] = 0;
 }
 
 #define VEC(...) ((const unsigned char[]){__VA_ARGS__})
@@ -113,8 +123,6 @@ static size_t zi_dotprod(const unsigned char *z, const unsigned char *v, size_t
        return y;
 }
 
-int __munmap(void *, size_t);
-
 static void do_tzset()
 {
        char buf[NAME_MAX+25], *pathname=buf+24;
@@ -130,6 +138,8 @@ static void do_tzset()
 
        if (old_tz && !strcmp(s, old_tz)) return;
 
+       for (i=0; i<5; i++) r0[i] = r1[i] = 0;
+
        if (zi) __munmap((void *)zi, map_size);
 
        /* Cache the old value of TZ to check if it has changed. Avoid
@@ -145,10 +155,21 @@ static void do_tzset()
        }
        if (old_tz) memcpy(old_tz, s, i+1);
 
+       int posix_form = 0;
+       if (*s != ':') {
+               p = s;
+               char dummy_name[TZNAME_MAX+1];
+               getname(dummy_name, &p);
+               if (p!=s && (*p == '+' || *p == '-' || isdigit(*p)
+                            || !strcmp(dummy_name, "UTC")
+                            || !strcmp(dummy_name, "GMT")))
+                       posix_form = 1;
+       }       
+
        /* 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 == ':' || ((p=strchr(s, '/')) && !memchr(s, ',', p-s))) {
+       if (!posix_form) {
                if (*s == ':') s++;
                if (*s == '/' || *s == '.') {
                        if (!libc.secure || !strcmp(s, "/etc/localtime"))
@@ -176,7 +197,7 @@ static void do_tzset()
        zi = map;
        if (map) {
                int scale = 2;
-               if (sizeof(time_t) > 4 && map[4]=='2') {
+               if (map[4]!='1') {
                        size_t skip = zi_dotprod(zi+20, VEC(1,1,8,5,6,1), 6);
                        trans = zi+skip+44+44;
                        scale++;
@@ -194,7 +215,6 @@ static void do_tzset()
                        const unsigned char *p;
                        __tzname[0] = __tzname[1] = 0;
                        __daylight = __timezone = dst_off = 0;
-                       for (i=0; i<5; i++) r0[i] = r1[i] = 0;
                        for (p=types; p<abbrevs; p+=6) {
                                if (!p[4] && !__tzname[0]) {
                                        __tzname[0] = (char *)abbrevs + p[5];
@@ -230,7 +250,7 @@ static void do_tzset()
                        dst_off = __timezone - 3600;
        } else {
                __daylight = 0;
-               dst_off = 0;
+               dst_off = __timezone;
        }
 
        if (*s == ',') s++, getrule(&s, r0);
@@ -273,22 +293,20 @@ static size_t scan_trans(long long t, int local, size_t *alt)
        n = (index-trans)>>scale;
        if (a == n-1) return -1;
        if (a == 0) {
-               x = zi_read32(trans + (a<<scale));
-               if (scale == 3) x = x<<32 | zi_read32(trans + (a<<scale) + 4);
+               x = zi_read32(trans);
+               if (scale == 3) x = x<<32 | zi_read32(trans + 4);
                else x = (int32_t)x;
-               if (local) off = (int32_t)zi_read32(types + 6 * index[a-1]);
+               /* Find the lowest non-DST type, or 0 if none. */
+               size_t j = 0;
+               for (size_t i=abbrevs-types; i; i-=6) {
+                       if (!types[i-6+4]) j = i-6;
+               }
+               if (local) off = (int32_t)zi_read32(types + j);
+               /* If t is before first transition, use the above-found type
+                * and the index-zero (after transition) type as the alt. */
                if (t - off < (int64_t)x) {
-                       for (a=0; a<(abbrevs-types)/6; a++) {
-                               if (types[6*a+4] != types[4]) break;
-                       }
-                       if (a == (abbrevs-types)/6) a = 0;
-                       if (types[6*a+4]) {
-                               *alt = a;
-                               return 0;
-                       } else {
-                               *alt = 0;
-                               return a;
-                       }
+                       if (alt) *alt = index[0];
+                       return j/6;
                }
        }
 
@@ -399,7 +417,7 @@ dst:
        UNLOCK(lock);
 }
 
-void __tzset()
+static void __tzset()
 {
        LOCK(lock);
        do_tzset();