Like tzset(), but in a critical section. If THREADED && THREAD_RWLOCK the caller has a read lock, and this function might upgrade it to a write lock. If WALL, act as if TZ is unset; although always false in this file, a wrapper .c file's obsolete and ineffective tzsetwall function can use it. If tz_change_interval is positive the time is NOW; otherwise ignore NOW. */
| 1885 | a wrapper .c file's obsolete and ineffective tzsetwall function can use it. |
| 1886 | If tz_change_interval is positive the time is NOW; otherwise ignore NOW. */ |
| 1887 | static void |
| 1888 | tzset_unlocked(bool threaded, bool wall, monotime_t now) |
| 1889 | { |
| 1890 | char const *name; |
| 1891 | struct state *sp; |
| 1892 | char tzloadflags; |
| 1893 | size_t namelen; |
| 1894 | bool writing = false; |
| 1895 | |
| 1896 | for (;;) { |
| 1897 | name = wall ? NULL : getenv("TZ"); |
| 1898 | sp = lclptr; |
| 1899 | tzloadflags = TZLOAD_FROMENV | TZLOAD_TZSTRING; |
| 1900 | namelen = sizeof lcl_TZname + 1; /* placeholder for no name */ |
| 1901 | |
| 1902 | if (name) { |
| 1903 | namelen = strnlen(name, sizeof lcl_TZname); |
| 1904 | |
| 1905 | /* Abbreviate a string like "/usr/share/zoneinfo/America/Los_Angeles" |
| 1906 | to its shorter equivalent "America/Los_Angeles". */ |
| 1907 | if (!SUPPRESS_TZDIR && tzdirslashlen < namelen |
| 1908 | && memcmp(name, tzdirslash, tzdirslashlen) == 0) { |
| 1909 | char const *p = name + tzdirslashlen; |
| 1910 | while (*p == '/') |
| 1911 | p++; |
| 1912 | if (*p && *p != ':') { |
| 1913 | name = p; |
| 1914 | namelen = strnlen(name, sizeof lcl_TZname); |
| 1915 | tzloadflags |= TZLOAD_TZDIR_SUB; |
| 1916 | } |
| 1917 | } |
| 1918 | } |
| 1919 | |
| 1920 | if ((tz_change_interval <= 0 ? tz_change_interval < 0 : fresh_tzdata(now)) |
| 1921 | && (name |
| 1922 | ? 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0 |
| 1923 | : lcl_is_set < 0)) |
| 1924 | return; |
| 1925 | |
| 1926 | if (!THREAD_RWLOCK || writing) |
| 1927 | break; |
| 1928 | if (rd2wrlock(threaded) != 0) |
| 1929 | return; |
| 1930 | writing = true; |
| 1931 | } |
| 1932 | |
| 1933 | # if ALL_STATE |
| 1934 | if (! sp) |
| 1935 | lclptr = sp = malloc(sizeof *lclptr); |
| 1936 | # endif |
| 1937 | if (sp) { |
| 1938 | int err = zoneinit(sp, name, tzloadflags); |
| 1939 | if (err != 0) { |
| 1940 | zoneinit(sp, "", 0); |
| 1941 | /* Abbreviate with "-00" if there was an error. |
| 1942 | Do not treat a missing TZDEFAULT file as an error. */ |
| 1943 | if (name || err != ENOENT) |
| 1944 | strcpy(sp->chars, UNSPEC); |
no test coverage detected