diff options
| author | Paul Eggert | 2014-10-11 23:09:50 -0700 |
|---|---|---|
| committer | Paul Eggert | 2014-10-11 23:09:50 -0700 |
| commit | 4c4c5b9121a550d006d1b57bc2ad97b0415cee9f (patch) | |
| tree | 3b5921413aeaa73741d0a234572f151a05e6f7bd /src | |
| parent | c1ec59da4905015d841ffeba9bb53a674b3a44f4 (diff) | |
| download | emacs-4c4c5b9121a550d006d1b57bc2ad97b0415cee9f.tar.gz emacs-4c4c5b9121a550d006d1b57bc2ad97b0415cee9f.zip | |
Fix putenv race conditions with undefined behavior.
Do all putenv calls before Emacs creates any threads.
Use a safer way to modify the TZ environment variable in the
presence of multiple threads. For further thread-safety,
prefer localtime_r and gmtime_r to localtime and gmtime,
and prefer struct tm's tm_gmtoff (if available) to calling
both localtime_r and gmtime_r.
* configure.ac (LOCALTIME_CACHE): Remove.
We needn't worry about SunOS 4 any more; Sun dropped support in 2003.
All uses of LOCALTIME_CACHE removed. This simplifies the fix.
(tzalloc): Add check for this function.
* admin/merge-gnulib (GNULIB_MODULES): Add time_r, since Emacs now
calls localtime_r and gmtime_r directly.
* src/dbusbind.c (Fdbus__init_bus): Move xputenv call from here ...
(init_dbusbind): ... to this new function.
* src/emacs.c (main) [HAVE_DBUS]: Call it before creating threads.
* src/xterm.c (x_term_init): Move xputenv call from here ...
(init_xterm): ... to this new function.
* src/emacs.c (main) [USE_GTK]: Call it before creating threads.
* src/editfns.c (HAVE_TM_GMTOFF): Default to false.
(dump_tz_string): New constant.
(init_editfns): Use it. This centralizes the dump_tz stuff.
Call set_time_zone_rule here, so that its xputenv is done
before Emacs goes multithreaded.
(mktime_z) [!HAVE_TZALLOC]: New function, which is typically
thread-safe enough for Emacs.
(format_time_string, Fdecode_time, Fcurrent_time_string)
(Fcurrent_time_zone):
Prefer localtime_r and gmtime_r, which are more thread-safe, to
localtime and gmtime. Remove now-unnecessary calls to block_input.
(tm_gmtoff): New static function.
(Fdecode_time, Fcurrent_time_zone): Use it.
(Fencode_time): Use mktime_z, for better thread-safety.
(set_time_zone_rule): Now static. Rewrite to be mostly thread-safe,
i.e., not quite thread-safe but good enough for Emacs typical usage.
Do not reclaim storage that is in the environment; let it leak.
Always call tzset, since localtime_r does not.
* src/emacs.c (dump_tz, Fdump_emacs) [HAVE_TZSET]: Remove dump_tz stuff.
This is now done in init_editfns.
* src/systime.h (mktime_z, timezone_t, tzalloc, tzfree) [!HAVE_TZALLOC]:
New macros and declarations, for platforms lacking tzalloc & friends.
Fixes: debbugs:8705
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 38 | ||||
| -rw-r--r-- | src/dbusbind.c | 11 | ||||
| -rw-r--r-- | src/editfns.c | 359 | ||||
| -rw-r--r-- | src/emacs.c | 62 | ||||
| -rw-r--r-- | src/lisp.h | 3 | ||||
| -rw-r--r-- | src/systime.h | 16 | ||||
| -rw-r--r-- | src/xterm.c | 13 |
7 files changed, 262 insertions, 240 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index f511aa19a19..568022f478b 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,41 @@ | |||
| 1 | 2014-10-12 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | Fix putenv race conditions with undefined behavior (Bug#8705). | ||
| 4 | Do all putenv calls before Emacs creates any threads. | ||
| 5 | Use a safer way to modify the TZ environment variable in the | ||
| 6 | presence of multiple threads. For further thread-safety, | ||
| 7 | prefer localtime_r and gmtime_r to localtime and gmtime, | ||
| 8 | and prefer struct tm's tm_gmtoff (if available) to calling | ||
| 9 | both localtime_r and gmtime_r. | ||
| 10 | * dbusbind.c (Fdbus__init_bus): Move xputenv call from here ... | ||
| 11 | (init_dbusbind): ... to this new function. | ||
| 12 | * emacs.c (main) [HAVE_DBUS]: Call it before creating threads. | ||
| 13 | * xterm.c (x_term_init): Move xputenv call from here ... | ||
| 14 | (init_xterm): ... to this new function. | ||
| 15 | * emacs.c (main) [USE_GTK]: Call it before creating threads. | ||
| 16 | * editfns.c (HAVE_TM_GMTOFF): Default to false. | ||
| 17 | (dump_tz_string): New constant. | ||
| 18 | (init_editfns): Use it. This centralizes the dump_tz stuff. | ||
| 19 | Call set_time_zone_rule here, so that its xputenv is done | ||
| 20 | before Emacs goes multithreaded. | ||
| 21 | (mktime_z) [!HAVE_TZALLOC]: New function, which is typically | ||
| 22 | thread-safe enough for Emacs. | ||
| 23 | (format_time_string, Fdecode_time, Fcurrent_time_string) | ||
| 24 | (Fcurrent_time_zone): | ||
| 25 | Prefer localtime_r and gmtime_r, which are more thread-safe, to | ||
| 26 | localtime and gmtime. Remove now-unnecessary calls to block_input. | ||
| 27 | (tm_gmtoff): New static function. | ||
| 28 | (Fdecode_time, Fcurrent_time_zone): Use it. | ||
| 29 | (Fencode_time): Use mktime_z, for better thread-safety. | ||
| 30 | (set_time_zone_rule): Now static. Rewrite to be mostly thread-safe, | ||
| 31 | i.e., not quite thread-safe but good enough for Emacs typical usage. | ||
| 32 | Do not reclaim storage that is in the environment; let it leak. | ||
| 33 | Always call tzset, since localtime_r does not. | ||
| 34 | * emacs.c (dump_tz, Fdump_emacs) [HAVE_TZSET]: Remove dump_tz stuff. | ||
| 35 | This is now done in init_editfns. | ||
| 36 | * systime.h (mktime_z, timezone_t, tzalloc, tzfree) [!HAVE_TZALLOC]: | ||
| 37 | New macros and declarations, for platforms lacking tzalloc & friends. | ||
| 38 | |||
| 1 | 2014-10-09 Paul Eggert <eggert@cs.ucla.edu> | 39 | 2014-10-09 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 40 | ||
| 3 | * lisp.h (USE_STACK_STRING): Now true only if USE_STACK CONS. | 41 | * lisp.h (USE_STACK_STRING): Now true only if USE_STACK CONS. |
diff --git a/src/dbusbind.c b/src/dbusbind.c index f81666ba7bd..4852739d8e4 100644 --- a/src/dbusbind.c +++ b/src/dbusbind.c | |||
| @@ -1054,6 +1054,7 @@ xd_remove_watch (DBusWatch *watch, void *data) | |||
| 1054 | 1054 | ||
| 1055 | /* Unset session environment. */ | 1055 | /* Unset session environment. */ |
| 1056 | #if 0 | 1056 | #if 0 |
| 1057 | /* This is buggy, since unsetenv is not thread-safe. */ | ||
| 1057 | if (XSYMBOL (QCdbus_session_bus) == data) | 1058 | if (XSYMBOL (QCdbus_session_bus) == data) |
| 1058 | { | 1059 | { |
| 1059 | XD_DEBUG_MESSAGE ("unsetenv DBUS_SESSION_BUS_ADDRESS"); | 1060 | XD_DEBUG_MESSAGE ("unsetenv DBUS_SESSION_BUS_ADDRESS"); |
| @@ -1219,9 +1220,6 @@ this connection to those buses. */) | |||
| 1219 | XSETFASTINT (val, (intptr_t) connection); | 1220 | XSETFASTINT (val, (intptr_t) connection); |
| 1220 | xd_registered_buses = Fcons (Fcons (bus, val), xd_registered_buses); | 1221 | xd_registered_buses = Fcons (Fcons (bus, val), xd_registered_buses); |
| 1221 | 1222 | ||
| 1222 | /* We do not want to abort. */ | ||
| 1223 | xputenv ("DBUS_FATAL_WARNINGS=0"); | ||
| 1224 | |||
| 1225 | /* Cleanup. */ | 1223 | /* Cleanup. */ |
| 1226 | dbus_error_free (&derror); | 1224 | dbus_error_free (&derror); |
| 1227 | } | 1225 | } |
| @@ -1738,6 +1736,13 @@ xd_read_queued_messages (int fd, void *data) | |||
| 1738 | 1736 | ||
| 1739 | 1737 | ||
| 1740 | void | 1738 | void |
| 1739 | init_dbusbind (void) | ||
| 1740 | { | ||
| 1741 | /* We do not want to abort. */ | ||
| 1742 | xputenv ("DBUS_FATAL_WARNINGS=0"); | ||
| 1743 | } | ||
| 1744 | |||
| 1745 | void | ||
| 1741 | syms_of_dbusbind (void) | 1746 | syms_of_dbusbind (void) |
| 1742 | { | 1747 | { |
| 1743 | 1748 | ||
diff --git a/src/editfns.c b/src/editfns.c index e7c960dfffe..d17d809c9ec 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -64,11 +64,17 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 64 | extern Lisp_Object w32_get_internal_run_time (void); | 64 | extern Lisp_Object w32_get_internal_run_time (void); |
| 65 | #endif | 65 | #endif |
| 66 | 66 | ||
| 67 | static void set_time_zone_rule (char const *); | ||
| 67 | static Lisp_Object format_time_string (char const *, ptrdiff_t, struct timespec, | 68 | static Lisp_Object format_time_string (char const *, ptrdiff_t, struct timespec, |
| 68 | bool, struct tm *); | 69 | bool, struct tm *); |
| 70 | static long int tm_gmtoff (struct tm *); | ||
| 69 | static int tm_diff (struct tm *, struct tm *); | 71 | static int tm_diff (struct tm *, struct tm *); |
| 70 | static void update_buffer_properties (ptrdiff_t, ptrdiff_t); | 72 | static void update_buffer_properties (ptrdiff_t, ptrdiff_t); |
| 71 | 73 | ||
| 74 | #ifndef HAVE_TM_GMTOFF | ||
| 75 | # define HAVE_TM_GMTOFF false | ||
| 76 | #endif | ||
| 77 | |||
| 72 | static Lisp_Object Qbuffer_access_fontify_functions; | 78 | static Lisp_Object Qbuffer_access_fontify_functions; |
| 73 | 79 | ||
| 74 | /* Symbol for the text property used to mark fields. */ | 80 | /* Symbol for the text property used to mark fields. */ |
| @@ -79,15 +85,12 @@ Lisp_Object Qfield; | |||
| 79 | 85 | ||
| 80 | static Lisp_Object Qboundary; | 86 | static Lisp_Object Qboundary; |
| 81 | 87 | ||
| 82 | /* The startup value of the TZ environment variable so it can be | 88 | /* The startup value of the TZ environment variable; null if unset. */ |
| 83 | restored if the user calls set-time-zone-rule with a nil | ||
| 84 | argument. If null, the TZ environment variable was unset. */ | ||
| 85 | static char const *initial_tz; | 89 | static char const *initial_tz; |
| 86 | 90 | ||
| 87 | /* True if the static variable tzvalbuf (defined in | 91 | /* A valid but unlikely setting for the TZ environment variable. |
| 88 | set_time_zone_rule) is part of 'environ'. */ | 92 | It is OK (though a bit slower) if the user chooses this value. */ |
| 89 | static bool tzvalbuf_in_environ; | 93 | static char const dump_tz_string[] = "TZ=UtC0"; |
| 90 | |||
| 91 | 94 | ||
| 92 | void | 95 | void |
| 93 | init_editfns (void) | 96 | init_editfns (void) |
| @@ -101,13 +104,38 @@ init_editfns (void) | |||
| 101 | init_system_name (); | 104 | init_system_name (); |
| 102 | 105 | ||
| 103 | #ifndef CANNOT_DUMP | 106 | #ifndef CANNOT_DUMP |
| 104 | /* Don't bother with this on initial start when just dumping out */ | 107 | /* When just dumping out, set the time zone to a known unlikely value |
| 108 | and skip the rest of this function. */ | ||
| 105 | if (!initialized) | 109 | if (!initialized) |
| 106 | return; | 110 | { |
| 107 | #endif /* not CANNOT_DUMP */ | 111 | # ifdef HAVE_TZSET |
| 112 | xputenv ((char *) dump_tz_string); | ||
| 113 | tzset (); | ||
| 114 | # endif | ||
| 115 | return; | ||
| 116 | } | ||
| 117 | #endif | ||
| 118 | |||
| 119 | char *tz = getenv ("TZ"); | ||
| 120 | initial_tz = tz; | ||
| 108 | 121 | ||
| 109 | initial_tz = getenv ("TZ"); | 122 | #if !defined CANNOT_DUMP && defined HAVE_TZSET |
| 110 | tzvalbuf_in_environ = 0; | 123 | /* If the execution TZ happens to be the same as the dump TZ, |
| 124 | change it to some other value and then change it back, | ||
| 125 | to force the underlying implementation to reload the TZ info. | ||
| 126 | This is needed on implementations that load TZ info from files, | ||
| 127 | since the TZ file contents may differ between dump and execution. */ | ||
| 128 | if (tz && strcmp (tz, &dump_tz_string[sizeof "TZ=" - 1]) == 0) | ||
| 129 | { | ||
| 130 | ++*tz; | ||
| 131 | tzset (); | ||
| 132 | --*tz; | ||
| 133 | } | ||
| 134 | #endif | ||
| 135 | |||
| 136 | /* Call set_time_zone_rule now, so that its call to putenv is done | ||
| 137 | before multiple threads are active. */ | ||
| 138 | set_time_zone_rule (tz); | ||
| 111 | 139 | ||
| 112 | pw = getpwuid (getuid ()); | 140 | pw = getpwuid (getuid ()); |
| 113 | #ifdef MSDOS | 141 | #ifdef MSDOS |
| @@ -1373,6 +1401,30 @@ time_overflow (void) | |||
| 1373 | error ("Specified time is not representable"); | 1401 | error ("Specified time is not representable"); |
| 1374 | } | 1402 | } |
| 1375 | 1403 | ||
| 1404 | /* A substitute for mktime_z on platforms that lack it. It's not | ||
| 1405 | thread-safe, but should be good enough for Emacs in typical use. */ | ||
| 1406 | #ifndef HAVE_TZALLOC | ||
| 1407 | time_t | ||
| 1408 | mktime_z (timezone_t tz, struct tm *tm) | ||
| 1409 | { | ||
| 1410 | char *oldtz = getenv ("TZ"); | ||
| 1411 | USE_SAFE_ALLOCA; | ||
| 1412 | if (oldtz) | ||
| 1413 | { | ||
| 1414 | size_t oldtzsize = strlen (oldtz) + 1; | ||
| 1415 | char *oldtzcopy = SAFE_ALLOCA (oldtzsize); | ||
| 1416 | oldtz = strcpy (oldtzcopy, oldtz); | ||
| 1417 | } | ||
| 1418 | block_input (); | ||
| 1419 | set_time_zone_rule (tz); | ||
| 1420 | time_t t = mktime (tm); | ||
| 1421 | set_time_zone_rule (oldtz); | ||
| 1422 | unblock_input (); | ||
| 1423 | SAFE_FREE (); | ||
| 1424 | return t; | ||
| 1425 | } | ||
| 1426 | #endif | ||
| 1427 | |||
| 1376 | /* Return the upper part of the time T (everything but the bottom 16 bits). */ | 1428 | /* Return the upper part of the time T (everything but the bottom 16 bits). */ |
| 1377 | static EMACS_INT | 1429 | static EMACS_INT |
| 1378 | hi_time (time_t t) | 1430 | hi_time (time_t t) |
| @@ -1768,39 +1820,28 @@ format_time_string (char const *format, ptrdiff_t formatlen, | |||
| 1768 | size_t len; | 1820 | size_t len; |
| 1769 | Lisp_Object bufstring; | 1821 | Lisp_Object bufstring; |
| 1770 | int ns = t.tv_nsec; | 1822 | int ns = t.tv_nsec; |
| 1771 | struct tm *tm; | ||
| 1772 | USE_SAFE_ALLOCA; | 1823 | USE_SAFE_ALLOCA; |
| 1773 | 1824 | ||
| 1774 | while (1) | 1825 | tmp = ut ? gmtime_r (&t.tv_sec, tmp) : localtime_r (&t.tv_sec, tmp); |
| 1775 | { | 1826 | if (! tmp) |
| 1776 | time_t *taddr = &t.tv_sec; | 1827 | time_overflow (); |
| 1777 | block_input (); | 1828 | synchronize_system_time_locale (); |
| 1778 | |||
| 1779 | synchronize_system_time_locale (); | ||
| 1780 | |||
| 1781 | tm = ut ? gmtime (taddr) : localtime (taddr); | ||
| 1782 | if (! tm) | ||
| 1783 | { | ||
| 1784 | unblock_input (); | ||
| 1785 | time_overflow (); | ||
| 1786 | } | ||
| 1787 | *tmp = *tm; | ||
| 1788 | 1829 | ||
| 1830 | while (true) | ||
| 1831 | { | ||
| 1789 | buf[0] = '\1'; | 1832 | buf[0] = '\1'; |
| 1790 | len = emacs_nmemftime (buf, size, format, formatlen, tm, ut, ns); | 1833 | len = emacs_nmemftime (buf, size, format, formatlen, tmp, ut, ns); |
| 1791 | if ((0 < len && len < size) || (len == 0 && buf[0] == '\0')) | 1834 | if ((0 < len && len < size) || (len == 0 && buf[0] == '\0')) |
| 1792 | break; | 1835 | break; |
| 1793 | 1836 | ||
| 1794 | /* Buffer was too small, so make it bigger and try again. */ | 1837 | /* Buffer was too small, so make it bigger and try again. */ |
| 1795 | len = emacs_nmemftime (NULL, SIZE_MAX, format, formatlen, tm, ut, ns); | 1838 | len = emacs_nmemftime (NULL, SIZE_MAX, format, formatlen, tmp, ut, ns); |
| 1796 | unblock_input (); | ||
| 1797 | if (STRING_BYTES_BOUND <= len) | 1839 | if (STRING_BYTES_BOUND <= len) |
| 1798 | string_overflow (); | 1840 | string_overflow (); |
| 1799 | size = len + 1; | 1841 | size = len + 1; |
| 1800 | buf = SAFE_ALLOCA (size); | 1842 | buf = SAFE_ALLOCA (size); |
| 1801 | } | 1843 | } |
| 1802 | 1844 | ||
| 1803 | unblock_input (); | ||
| 1804 | bufstring = make_unibyte_string (buf, len); | 1845 | bufstring = make_unibyte_string (buf, len); |
| 1805 | SAFE_FREE (); | 1846 | SAFE_FREE (); |
| 1806 | return code_convert_string_norecord (bufstring, Vlocale_coding_system, 0); | 1847 | return code_convert_string_norecord (bufstring, Vlocale_coding_system, 0); |
| @@ -1824,38 +1865,30 @@ DOW and ZONE.) */) | |||
| 1824 | (Lisp_Object specified_time) | 1865 | (Lisp_Object specified_time) |
| 1825 | { | 1866 | { |
| 1826 | time_t time_spec = lisp_seconds_argument (specified_time); | 1867 | time_t time_spec = lisp_seconds_argument (specified_time); |
| 1827 | struct tm save_tm; | 1868 | struct tm local_tm, gmt_tm; |
| 1828 | struct tm *decoded_time; | ||
| 1829 | Lisp_Object list_args[9]; | ||
| 1830 | 1869 | ||
| 1831 | block_input (); | 1870 | if (! (localtime_r (&time_spec, &local_tm) |
| 1832 | decoded_time = localtime (&time_spec); | 1871 | && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= local_tm.tm_year |
| 1833 | if (decoded_time) | 1872 | && local_tm.tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE)) |
| 1834 | save_tm = *decoded_time; | ||
| 1835 | unblock_input (); | ||
| 1836 | if (! (decoded_time | ||
| 1837 | && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= save_tm.tm_year | ||
| 1838 | && save_tm.tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE)) | ||
| 1839 | time_overflow (); | 1873 | time_overflow (); |
| 1840 | XSETFASTINT (list_args[0], save_tm.tm_sec); | ||
| 1841 | XSETFASTINT (list_args[1], save_tm.tm_min); | ||
| 1842 | XSETFASTINT (list_args[2], save_tm.tm_hour); | ||
| 1843 | XSETFASTINT (list_args[3], save_tm.tm_mday); | ||
| 1844 | XSETFASTINT (list_args[4], save_tm.tm_mon + 1); | ||
| 1845 | /* On 64-bit machines an int is narrower than EMACS_INT, thus the | ||
| 1846 | cast below avoids overflow in int arithmetics. */ | ||
| 1847 | XSETINT (list_args[5], TM_YEAR_BASE + (EMACS_INT) save_tm.tm_year); | ||
| 1848 | XSETFASTINT (list_args[6], save_tm.tm_wday); | ||
| 1849 | list_args[7] = save_tm.tm_isdst ? Qt : Qnil; | ||
| 1850 | 1874 | ||
| 1851 | block_input (); | 1875 | /* Avoid overflow when INT_MAX < EMACS_INT_MAX. */ |
| 1852 | decoded_time = gmtime (&time_spec); | 1876 | EMACS_INT tm_year_base = TM_YEAR_BASE; |
| 1853 | if (decoded_time == 0) | 1877 | |
| 1854 | list_args[8] = Qnil; | 1878 | return Flist (9, ((Lisp_Object []) |
| 1855 | else | 1879 | {make_number (local_tm.tm_sec), |
| 1856 | XSETINT (list_args[8], tm_diff (&save_tm, decoded_time)); | 1880 | make_number (local_tm.tm_min), |
| 1857 | unblock_input (); | 1881 | make_number (local_tm.tm_hour), |
| 1858 | return Flist (9, list_args); | 1882 | make_number (local_tm.tm_mday), |
| 1883 | make_number (local_tm.tm_mon + 1), | ||
| 1884 | make_number (local_tm.tm_year + tm_year_base), | ||
| 1885 | make_number (local_tm.tm_wday), | ||
| 1886 | local_tm.tm_isdst ? Qt : Qnil, | ||
| 1887 | (HAVE_TM_GMTOFF | ||
| 1888 | ? make_number (tm_gmtoff (&local_tm)) | ||
| 1889 | : gmtime_r (&time_spec, &gmt_tm) | ||
| 1890 | ? make_number (tm_diff (&local_tm, &gmt_tm)) | ||
| 1891 | : Qnil)})); | ||
| 1859 | } | 1892 | } |
| 1860 | 1893 | ||
| 1861 | /* Return OBJ - OFFSET, checking that OBJ is a valid fixnum and that | 1894 | /* Return OBJ - OFFSET, checking that OBJ is a valid fixnum and that |
| @@ -1911,18 +1944,12 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */) | |||
| 1911 | if (CONSP (zone)) | 1944 | if (CONSP (zone)) |
| 1912 | zone = XCAR (zone); | 1945 | zone = XCAR (zone); |
| 1913 | if (NILP (zone)) | 1946 | if (NILP (zone)) |
| 1914 | { | 1947 | value = mktime (&tm); |
| 1915 | block_input (); | ||
| 1916 | value = mktime (&tm); | ||
| 1917 | unblock_input (); | ||
| 1918 | } | ||
| 1919 | else | 1948 | else |
| 1920 | { | 1949 | { |
| 1921 | static char const tzbuf_format[] = "XXX%s%"pI"d:%02d:%02d"; | 1950 | static char const tzbuf_format[] = "XXX%s%"pI"d:%02d:%02d"; |
| 1922 | char tzbuf[sizeof tzbuf_format + INT_STRLEN_BOUND (EMACS_INT)]; | 1951 | char tzbuf[sizeof tzbuf_format + INT_STRLEN_BOUND (EMACS_INT)]; |
| 1923 | char *old_tzstring; | ||
| 1924 | const char *tzstring; | 1952 | const char *tzstring; |
| 1925 | USE_SAFE_ALLOCA; | ||
| 1926 | 1953 | ||
| 1927 | if (EQ (zone, Qt)) | 1954 | if (EQ (zone, Qt)) |
| 1928 | tzstring = "UTC0"; | 1955 | tzstring = "UTC0"; |
| @@ -1939,29 +1966,13 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */) | |||
| 1939 | tzstring = tzbuf; | 1966 | tzstring = tzbuf; |
| 1940 | } | 1967 | } |
| 1941 | else | 1968 | else |
| 1942 | error ("Invalid time zone specification"); | 1969 | tzstring = 0; |
| 1943 | 1970 | ||
| 1944 | old_tzstring = getenv ("TZ"); | 1971 | timezone_t tz = tzstring ? tzalloc (tzstring) : 0; |
| 1945 | if (old_tzstring) | 1972 | if (! tz) |
| 1946 | { | 1973 | error ("Invalid time zone specification"); |
| 1947 | char *buf = SAFE_ALLOCA (strlen (old_tzstring) + 1); | 1974 | value = mktime_z (tz, &tm); |
| 1948 | old_tzstring = strcpy (buf, old_tzstring); | 1975 | tzfree (tz); |
| 1949 | } | ||
| 1950 | |||
| 1951 | block_input (); | ||
| 1952 | |||
| 1953 | /* Set TZ before calling mktime; merely adjusting mktime's returned | ||
| 1954 | value doesn't suffice, since that would mishandle leap seconds. */ | ||
| 1955 | set_time_zone_rule (tzstring); | ||
| 1956 | |||
| 1957 | value = mktime (&tm); | ||
| 1958 | |||
| 1959 | set_time_zone_rule (old_tzstring); | ||
| 1960 | #ifdef LOCALTIME_CACHE | ||
| 1961 | tzset (); | ||
| 1962 | #endif | ||
| 1963 | unblock_input (); | ||
| 1964 | SAFE_FREE (); | ||
| 1965 | } | 1976 | } |
| 1966 | 1977 | ||
| 1967 | if (value == (time_t) -1) | 1978 | if (value == (time_t) -1) |
| @@ -1987,34 +1998,27 @@ but this is considered obsolete. */) | |||
| 1987 | (Lisp_Object specified_time) | 1998 | (Lisp_Object specified_time) |
| 1988 | { | 1999 | { |
| 1989 | time_t value = lisp_seconds_argument (specified_time); | 2000 | time_t value = lisp_seconds_argument (specified_time); |
| 1990 | struct tm *tm; | ||
| 1991 | char buf[sizeof "Mon Apr 30 12:49:17 " + INT_STRLEN_BOUND (int) + 1]; | ||
| 1992 | int len IF_LINT (= 0); | ||
| 1993 | 2001 | ||
| 1994 | /* Convert to a string in ctime format, except without the trailing | 2002 | /* Convert to a string in ctime format, except without the trailing |
| 1995 | newline, and without the 4-digit year limit. Don't use asctime | 2003 | newline, and without the 4-digit year limit. Don't use asctime |
| 1996 | or ctime, as they might dump core if the year is outside the | 2004 | or ctime, as they might dump core if the year is outside the |
| 1997 | range -999 .. 9999. */ | 2005 | range -999 .. 9999. */ |
| 1998 | block_input (); | 2006 | struct tm tm; |
| 1999 | tm = localtime (&value); | 2007 | if (! localtime_r (&value, &tm)) |
| 2000 | if (tm) | ||
| 2001 | { | ||
| 2002 | static char const wday_name[][4] = | ||
| 2003 | { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; | ||
| 2004 | static char const mon_name[][4] = | ||
| 2005 | { "Jan", "Feb", "Mar", "Apr", "May", "Jun", | ||
| 2006 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; | ||
| 2007 | printmax_t year_base = TM_YEAR_BASE; | ||
| 2008 | |||
| 2009 | len = sprintf (buf, "%s %s%3d %02d:%02d:%02d %"pMd, | ||
| 2010 | wday_name[tm->tm_wday], mon_name[tm->tm_mon], tm->tm_mday, | ||
| 2011 | tm->tm_hour, tm->tm_min, tm->tm_sec, | ||
| 2012 | tm->tm_year + year_base); | ||
| 2013 | } | ||
| 2014 | unblock_input (); | ||
| 2015 | if (! tm) | ||
| 2016 | time_overflow (); | 2008 | time_overflow (); |
| 2017 | 2009 | ||
| 2010 | static char const wday_name[][4] = | ||
| 2011 | { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; | ||
| 2012 | static char const mon_name[][4] = | ||
| 2013 | { "Jan", "Feb", "Mar", "Apr", "May", "Jun", | ||
| 2014 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; | ||
| 2015 | printmax_t year_base = TM_YEAR_BASE; | ||
| 2016 | char buf[sizeof "Mon Apr 30 12:49:17 " + INT_STRLEN_BOUND (int) + 1]; | ||
| 2017 | int len = sprintf (buf, "%s %s%3d %02d:%02d:%02d %"pMd, | ||
| 2018 | wday_name[tm.tm_wday], mon_name[tm.tm_mon], tm.tm_mday, | ||
| 2019 | tm.tm_hour, tm.tm_min, tm.tm_sec, | ||
| 2020 | tm.tm_year + year_base); | ||
| 2021 | |||
| 2018 | return make_unibyte_string (buf, len); | 2022 | return make_unibyte_string (buf, len); |
| 2019 | } | 2023 | } |
| 2020 | 2024 | ||
| @@ -2041,6 +2045,17 @@ tm_diff (struct tm *a, struct tm *b) | |||
| 2041 | + (a->tm_sec - b->tm_sec)); | 2045 | + (a->tm_sec - b->tm_sec)); |
| 2042 | } | 2046 | } |
| 2043 | 2047 | ||
| 2048 | /* Yield A's UTC offset, or an unspecified value if unknown. */ | ||
| 2049 | static long int | ||
| 2050 | tm_gmtoff (struct tm *a) | ||
| 2051 | { | ||
| 2052 | #if HAVE_TM_GMTOFF | ||
| 2053 | return a->tm_gmtoff; | ||
| 2054 | #else | ||
| 2055 | return 0; | ||
| 2056 | #endif | ||
| 2057 | } | ||
| 2058 | |||
| 2044 | DEFUN ("current-time-zone", Fcurrent_time_zone, Scurrent_time_zone, 0, 1, 0, | 2059 | DEFUN ("current-time-zone", Fcurrent_time_zone, Scurrent_time_zone, 0, 1, 0, |
| 2045 | doc: /* Return the offset and name for the local time zone. | 2060 | doc: /* Return the offset and name for the local time zone. |
| 2046 | This returns a list of the form (OFFSET NAME). | 2061 | This returns a list of the form (OFFSET NAME). |
| @@ -2059,32 +2074,30 @@ the data it can't find. */) | |||
| 2059 | (Lisp_Object specified_time) | 2074 | (Lisp_Object specified_time) |
| 2060 | { | 2075 | { |
| 2061 | struct timespec value; | 2076 | struct timespec value; |
| 2062 | int offset; | 2077 | struct tm local_tm, gmt_tm; |
| 2063 | struct tm *t; | ||
| 2064 | struct tm localtm; | ||
| 2065 | Lisp_Object zone_offset, zone_name; | 2078 | Lisp_Object zone_offset, zone_name; |
| 2066 | 2079 | ||
| 2067 | zone_offset = Qnil; | 2080 | zone_offset = Qnil; |
| 2068 | value = make_timespec (lisp_seconds_argument (specified_time), 0); | 2081 | value = make_timespec (lisp_seconds_argument (specified_time), 0); |
| 2069 | zone_name = format_time_string ("%Z", sizeof "%Z" - 1, value, 0, &localtm); | 2082 | zone_name = format_time_string ("%Z", sizeof "%Z" - 1, value, 0, &local_tm); |
| 2070 | block_input (); | ||
| 2071 | t = gmtime (&value.tv_sec); | ||
| 2072 | if (t) | ||
| 2073 | offset = tm_diff (&localtm, t); | ||
| 2074 | unblock_input (); | ||
| 2075 | 2083 | ||
| 2076 | if (t) | 2084 | if (HAVE_TM_GMTOFF || gmtime_r (&value.tv_sec, &gmt_tm)) |
| 2077 | { | 2085 | { |
| 2086 | long int offset = (HAVE_TM_GMTOFF | ||
| 2087 | ? tm_gmtoff (&local_tm) | ||
| 2088 | : tm_diff (&local_tm, &gmt_tm)); | ||
| 2078 | zone_offset = make_number (offset); | 2089 | zone_offset = make_number (offset); |
| 2079 | if (SCHARS (zone_name) == 0) | 2090 | if (SCHARS (zone_name) == 0) |
| 2080 | { | 2091 | { |
| 2081 | /* No local time zone name is available; use "+-NNNN" instead. */ | 2092 | /* No local time zone name is available; use "+-NNNN" instead. */ |
| 2082 | int m = offset / 60; | 2093 | long int m = offset / 60; |
| 2083 | int am = offset < 0 ? - m : m; | 2094 | long int am = offset < 0 ? - m : m; |
| 2084 | char buf[sizeof "+00" + INT_STRLEN_BOUND (int)]; | 2095 | long int hour = am / 60; |
| 2085 | zone_name = make_formatted_string (buf, "%c%02d%02d", | 2096 | int min = am % 60; |
| 2097 | char buf[sizeof "+00" + INT_STRLEN_BOUND (long int)]; | ||
| 2098 | zone_name = make_formatted_string (buf, "%c%02ld%02d", | ||
| 2086 | (offset < 0 ? '-' : '+'), | 2099 | (offset < 0 ? '-' : '+'), |
| 2087 | am / 60, am % 60); | 2100 | hour, min); |
| 2088 | } | 2101 | } |
| 2089 | } | 2102 | } |
| 2090 | 2103 | ||
| @@ -2123,12 +2136,12 @@ only the former. */) | |||
| 2123 | 2136 | ||
| 2124 | /* Set the local time zone rule to TZSTRING. | 2137 | /* Set the local time zone rule to TZSTRING. |
| 2125 | 2138 | ||
| 2126 | This function is not thread-safe, partly because putenv, unsetenv | 2139 | This function is not thread-safe, in theory because putenv is not, |
| 2127 | and tzset are not, and partly because of the static storage it | 2140 | but mostly because of the static storage it updates. Other threads |
| 2128 | updates. Other threads that invoke localtime etc. may be adversely | 2141 | that invoke localtime etc. may be adversely affected while this |
| 2129 | affected while this function is executing. */ | 2142 | function is executing. */ |
| 2130 | 2143 | ||
| 2131 | void | 2144 | static void |
| 2132 | set_time_zone_rule (const char *tzstring) | 2145 | set_time_zone_rule (const char *tzstring) |
| 2133 | { | 2146 | { |
| 2134 | /* A buffer holding a string of the form "TZ=value", intended | 2147 | /* A buffer holding a string of the form "TZ=value", intended |
| @@ -2137,75 +2150,47 @@ set_time_zone_rule (const char *tzstring) | |||
| 2137 | static ptrdiff_t tzvalbufsize; | 2150 | static ptrdiff_t tzvalbufsize; |
| 2138 | 2151 | ||
| 2139 | int tzeqlen = sizeof "TZ=" - 1; | 2152 | int tzeqlen = sizeof "TZ=" - 1; |
| 2153 | ptrdiff_t tzstringlen = tzstring ? strlen (tzstring) : 0; | ||
| 2154 | char *tzval = tzvalbuf; | ||
| 2155 | bool new_tzvalbuf = tzvalbufsize <= tzeqlen + tzstringlen; | ||
| 2140 | 2156 | ||
| 2141 | #ifdef LOCALTIME_CACHE | 2157 | if (new_tzvalbuf) |
| 2142 | /* These two values are known to load tz files in buggy implementations, | 2158 | { |
| 2143 | i.e., Solaris 1 executables running under either Solaris 1 or Solaris 2. | 2159 | /* Do not attempt to free the old tzvalbuf, since another thread |
| 2144 | Their values shouldn't matter in non-buggy implementations. | 2160 | may be using it. In practice, the first allocation is large |
| 2145 | We don't use string literals for these strings, | 2161 | enough and memory does not leak. */ |
| 2146 | since if a string in the environment is in readonly | 2162 | tzval = xpalloc (NULL, &tzvalbufsize, |
| 2147 | storage, it runs afoul of bugs in SVR4 and Solaris 2.3. | 2163 | tzeqlen + tzstringlen - tzvalbufsize + 1, -1, 1); |
| 2148 | See Sun bugs 1113095 and 1114114, ``Timezone routines | 2164 | tzvalbuf = tzval; |
| 2149 | improperly modify environment''. */ | 2165 | tzval[1] = 'Z'; |
| 2150 | 2166 | tzval[2] = '='; | |
| 2151 | static char set_time_zone_rule_tz[][sizeof "TZ=GMT+0"] | 2167 | } |
| 2152 | = { "TZ=GMT+0", "TZ=GMT+1" }; | ||
| 2153 | |||
| 2154 | /* In SunOS 4.1.3_U1 and 4.1.4, if TZ has a value like | ||
| 2155 | "US/Pacific" that loads a tz file, then changes to a value like | ||
| 2156 | "XXX0" that does not load a tz file, and then changes back to | ||
| 2157 | its original value, the last change is (incorrectly) ignored. | ||
| 2158 | Also, if TZ changes twice in succession to values that do | ||
| 2159 | not load a tz file, tzset can dump core (see Sun bug#1225179). | ||
| 2160 | The following code works around these bugs. */ | ||
| 2161 | 2168 | ||
| 2162 | if (tzstring) | 2169 | if (tzstring) |
| 2163 | { | 2170 | { |
| 2164 | /* Temporarily set TZ to a value that loads a tz file | 2171 | /* Modify TZVAL in place. Although this is dicey in a |
| 2165 | and that differs from tzstring. */ | 2172 | multithreaded environment, we know of no portable alternative. |
| 2166 | bool eq0 = strcmp (tzstring, set_time_zone_rule_tz[0] + tzeqlen) == 0; | 2173 | Calling putenv or setenv could crash some other thread. */ |
| 2167 | xputenv (set_time_zone_rule_tz[eq0]); | 2174 | tzval[0] = 'T'; |
| 2175 | strcpy (tzval + tzeqlen, tzstring); | ||
| 2168 | } | 2176 | } |
| 2169 | else | 2177 | else |
| 2170 | { | 2178 | { |
| 2171 | /* The implied tzstring is unknown, so temporarily set TZ to | 2179 | /* Turn 'TZ=whatever' into an empty environment variable 'tZ='. |
| 2172 | two different values that each load a tz file. */ | 2180 | Although this is also dicey, calling unsetenv here can crash Emacs. |
| 2173 | xputenv (set_time_zone_rule_tz[0]); | 2181 | See Bug#8705. */ |
| 2174 | tzset (); | 2182 | tzval[0] = 't'; |
| 2175 | xputenv (set_time_zone_rule_tz[1]); | 2183 | tzval[tzeqlen] = 0; |
| 2176 | } | 2184 | } |
| 2177 | tzset (); | ||
| 2178 | tzvalbuf_in_environ = 0; | ||
| 2179 | #endif | ||
| 2180 | 2185 | ||
| 2181 | if (!tzstring) | 2186 | if (new_tzvalbuf) |
| 2182 | { | ||
| 2183 | unsetenv ("TZ"); | ||
| 2184 | tzvalbuf_in_environ = 0; | ||
| 2185 | } | ||
| 2186 | else | ||
| 2187 | { | 2187 | { |
| 2188 | ptrdiff_t tzstringlen = strlen (tzstring); | 2188 | /* Although this is not thread-safe, in practice this runs only |
| 2189 | 2189 | on startup when there is only one thread. */ | |
| 2190 | if (tzvalbufsize <= tzeqlen + tzstringlen) | 2190 | xputenv (tzval); |
| 2191 | { | ||
| 2192 | unsetenv ("TZ"); | ||
| 2193 | tzvalbuf_in_environ = 0; | ||
| 2194 | tzvalbuf = xpalloc (tzvalbuf, &tzvalbufsize, | ||
| 2195 | tzeqlen + tzstringlen - tzvalbufsize + 1, -1, 1); | ||
| 2196 | memcpy (tzvalbuf, "TZ=", tzeqlen); | ||
| 2197 | } | ||
| 2198 | |||
| 2199 | strcpy (tzvalbuf + tzeqlen, tzstring); | ||
| 2200 | |||
| 2201 | if (!tzvalbuf_in_environ) | ||
| 2202 | { | ||
| 2203 | xputenv (tzvalbuf); | ||
| 2204 | tzvalbuf_in_environ = 1; | ||
| 2205 | } | ||
| 2206 | } | 2191 | } |
| 2207 | 2192 | ||
| 2208 | #ifdef LOCALTIME_CACHE | 2193 | #ifdef HAVE_TZSET |
| 2209 | tzset (); | 2194 | tzset (); |
| 2210 | #endif | 2195 | #endif |
| 2211 | } | 2196 | } |
diff --git a/src/emacs.c b/src/emacs.c index 60b67b5a902..90182e53e70 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -578,12 +578,6 @@ DEFUN ("invocation-directory", Finvocation_directory, Sinvocation_directory, | |||
| 578 | } | 578 | } |
| 579 | 579 | ||
| 580 | 580 | ||
| 581 | #ifdef HAVE_TZSET | ||
| 582 | /* A valid but unlikely value for the TZ environment value. | ||
| 583 | It is OK (though a bit slower) if the user actually chooses this value. */ | ||
| 584 | static char const dump_tz[] = "UtC0"; | ||
| 585 | #endif | ||
| 586 | |||
| 587 | /* Test whether the next argument in ARGV matches SSTR or a prefix of | 581 | /* Test whether the next argument in ARGV matches SSTR or a prefix of |
| 588 | LSTR (at least MINLEN characters). If so, then if VALPTR is non-null | 582 | LSTR (at least MINLEN characters). If so, then if VALPTR is non-null |
| 589 | (the argument is supposed to have a value) store in *VALPTR either | 583 | (the argument is supposed to have a value) store in *VALPTR either |
| @@ -1548,8 +1542,23 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 1548 | 1542 | ||
| 1549 | init_charset (); | 1543 | init_charset (); |
| 1550 | 1544 | ||
| 1551 | init_editfns (); /* init_process_emacs uses Voperating_system_release. */ | 1545 | /* This calls putenv and so must precede init_process_emacs. Also, |
| 1552 | init_process_emacs (); /* init_display uses add_keyboard_wait_descriptor. */ | 1546 | it sets Voperating_system_release, which init_process_emacs uses. */ |
| 1547 | init_editfns (); | ||
| 1548 | |||
| 1549 | /* These two call putenv. */ | ||
| 1550 | #ifdef HAVE_DBUS | ||
| 1551 | init_dbusbind (); | ||
| 1552 | #endif | ||
| 1553 | #ifdef USE_GTK | ||
| 1554 | init_xterm (); | ||
| 1555 | #endif | ||
| 1556 | |||
| 1557 | /* This can create a thread that may call getenv, so it must follow | ||
| 1558 | all calls to putenv and setenv. Also, this sets up | ||
| 1559 | add_keyboard_wait_descriptor, which init_display uses. */ | ||
| 1560 | init_process_emacs (); | ||
| 1561 | |||
| 1553 | init_keyboard (); /* This too must precede init_sys_modes. */ | 1562 | init_keyboard (); /* This too must precede init_sys_modes. */ |
| 1554 | if (!noninteractive) | 1563 | if (!noninteractive) |
| 1555 | init_display (); /* Determine terminal type. Calls init_sys_modes. */ | 1564 | init_display (); /* Determine terminal type. Calls init_sys_modes. */ |
| @@ -1586,26 +1595,6 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 1586 | build_string ("loadup.el")); | 1595 | build_string ("loadup.el")); |
| 1587 | } | 1596 | } |
| 1588 | 1597 | ||
| 1589 | if (initialized) | ||
| 1590 | { | ||
| 1591 | #ifdef HAVE_TZSET | ||
| 1592 | { | ||
| 1593 | /* If the execution TZ happens to be the same as the dump TZ, | ||
| 1594 | change it to some other value and then change it back, | ||
| 1595 | to force the underlying implementation to reload the TZ info. | ||
| 1596 | This is needed on implementations that load TZ info from files, | ||
| 1597 | since the TZ file contents may differ between dump and execution. */ | ||
| 1598 | char *tz = getenv ("TZ"); | ||
| 1599 | if (tz && !strcmp (tz, dump_tz)) | ||
| 1600 | { | ||
| 1601 | ++*tz; | ||
| 1602 | tzset (); | ||
| 1603 | --*tz; | ||
| 1604 | } | ||
| 1605 | } | ||
| 1606 | #endif | ||
| 1607 | } | ||
| 1608 | |||
| 1609 | /* Set up for profiling. This is known to work on FreeBSD, | 1598 | /* Set up for profiling. This is known to work on FreeBSD, |
| 1610 | GNU/Linux and MinGW. It might work on some other systems too. | 1599 | GNU/Linux and MinGW. It might work on some other systems too. |
| 1611 | Give it a try and tell us if it works on your system. To compile | 1600 | Give it a try and tell us if it works on your system. To compile |
| @@ -1630,15 +1619,6 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 1630 | 1619 | ||
| 1631 | initialized = 1; | 1620 | initialized = 1; |
| 1632 | 1621 | ||
| 1633 | #ifdef LOCALTIME_CACHE | ||
| 1634 | /* Some versions of localtime have a bug. They cache the value of the time | ||
| 1635 | zone rather than looking it up every time. Since localtime() is | ||
| 1636 | called to bolt the undumping time into the undumped emacs, this | ||
| 1637 | results in localtime ignoring the TZ environment variable. | ||
| 1638 | This flushes the new TZ value into localtime. */ | ||
| 1639 | tzset (); | ||
| 1640 | #endif /* defined (LOCALTIME_CACHE) */ | ||
| 1641 | |||
| 1642 | /* Enter editor command loop. This never returns. */ | 1622 | /* Enter editor command loop. This never returns. */ |
| 1643 | Frecursive_edit (); | 1623 | Frecursive_edit (); |
| 1644 | /* NOTREACHED */ | 1624 | /* NOTREACHED */ |
| @@ -2119,14 +2099,6 @@ You must run Emacs in batch mode in order to dump it. */) | |||
| 2119 | tem = Vpurify_flag; | 2099 | tem = Vpurify_flag; |
| 2120 | Vpurify_flag = Qnil; | 2100 | Vpurify_flag = Qnil; |
| 2121 | 2101 | ||
| 2122 | #ifdef HAVE_TZSET | ||
| 2123 | set_time_zone_rule (dump_tz); | ||
| 2124 | #ifndef LOCALTIME_CACHE | ||
| 2125 | /* Force a tz reload, since set_time_zone_rule doesn't. */ | ||
| 2126 | tzset (); | ||
| 2127 | #endif | ||
| 2128 | #endif | ||
| 2129 | |||
| 2130 | fflush (stdout); | 2102 | fflush (stdout); |
| 2131 | /* Tell malloc where start of impure now is. */ | 2103 | /* Tell malloc where start of impure now is. */ |
| 2132 | /* Also arrange for warnings when nearly out of space. */ | 2104 | /* Also arrange for warnings when nearly out of space. */ |
diff --git a/src/lisp.h b/src/lisp.h index 9e4cc5fdc53..89f29ea268b 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3990,7 +3990,6 @@ extern Lisp_Object make_buffer_string_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, | |||
| 3990 | ptrdiff_t, bool); | 3990 | ptrdiff_t, bool); |
| 3991 | extern void init_editfns (void); | 3991 | extern void init_editfns (void); |
| 3992 | extern void syms_of_editfns (void); | 3992 | extern void syms_of_editfns (void); |
| 3993 | extern void set_time_zone_rule (const char *); | ||
| 3994 | 3993 | ||
| 3995 | /* Defined in buffer.c. */ | 3994 | /* Defined in buffer.c. */ |
| 3996 | extern bool mouse_face_overlay_overlaps (Lisp_Object); | 3995 | extern bool mouse_face_overlay_overlaps (Lisp_Object); |
| @@ -4398,6 +4397,7 @@ extern void syms_of_xsmfns (void); | |||
| 4398 | extern void syms_of_xselect (void); | 4397 | extern void syms_of_xselect (void); |
| 4399 | 4398 | ||
| 4400 | /* Defined in xterm.c. */ | 4399 | /* Defined in xterm.c. */ |
| 4400 | extern void init_xterm (void); | ||
| 4401 | extern void syms_of_xterm (void); | 4401 | extern void syms_of_xterm (void); |
| 4402 | #endif /* HAVE_X_WINDOWS */ | 4402 | #endif /* HAVE_X_WINDOWS */ |
| 4403 | 4403 | ||
| @@ -4419,6 +4419,7 @@ extern void syms_of_decompress (void); | |||
| 4419 | 4419 | ||
| 4420 | #ifdef HAVE_DBUS | 4420 | #ifdef HAVE_DBUS |
| 4421 | /* Defined in dbusbind.c. */ | 4421 | /* Defined in dbusbind.c. */ |
| 4422 | void init_dbusbind (void); | ||
| 4422 | void syms_of_dbusbind (void); | 4423 | void syms_of_dbusbind (void); |
| 4423 | #endif | 4424 | #endif |
| 4424 | 4425 | ||
diff --git a/src/systime.h b/src/systime.h index a834bce76dc..8f018044660 100644 --- a/src/systime.h +++ b/src/systime.h | |||
| @@ -93,6 +93,22 @@ extern bool decode_time_components (Lisp_Object, Lisp_Object, Lisp_Object, | |||
| 93 | extern struct timespec lisp_time_argument (Lisp_Object); | 93 | extern struct timespec lisp_time_argument (Lisp_Object); |
| 94 | #endif | 94 | #endif |
| 95 | 95 | ||
| 96 | #ifndef HAVE_TZALLOC | ||
| 97 | # undef mktime_z | ||
| 98 | # undef timezone_t | ||
| 99 | # undef tzalloc | ||
| 100 | # undef tzfree | ||
| 101 | # define mktime_z emacs_mktime_z | ||
| 102 | # define timezone_t emacs_timezone_t | ||
| 103 | # define tzalloc emacs_tzalloc | ||
| 104 | # define tzfree emacs_tzfree | ||
| 105 | typedef char const *timezone_t; | ||
| 106 | INLINE timezone_t tzalloc (char const *name) { return name; } | ||
| 107 | INLINE void tzfree (timezone_t tz) { } | ||
| 108 | /* Defined in editfns.c. */ | ||
| 109 | extern time_t mktime_z (timezone_t, struct tm *); | ||
| 110 | #endif | ||
| 111 | |||
| 96 | INLINE_HEADER_END | 112 | INLINE_HEADER_END |
| 97 | 113 | ||
| 98 | #endif /* EMACS_SYSTIME_H */ | 114 | #endif /* EMACS_SYSTIME_H */ |
diff --git a/src/xterm.c b/src/xterm.c index aff57f6a17e..f32aea031f9 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -10717,10 +10717,6 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) | |||
| 10717 | 10717 | ||
| 10718 | XSetLocaleModifiers (""); | 10718 | XSetLocaleModifiers (""); |
| 10719 | 10719 | ||
| 10720 | /* Emacs can only handle core input events, so make sure | ||
| 10721 | Gtk doesn't use Xinput or Xinput2 extensions. */ | ||
| 10722 | xputenv ("GDK_CORE_DEVICE_EVENTS=1"); | ||
| 10723 | |||
| 10724 | /* Work around GLib bug that outputs a faulty warning. See | 10720 | /* Work around GLib bug that outputs a faulty warning. See |
| 10725 | https://bugzilla.gnome.org/show_bug.cgi?id=563627. */ | 10721 | https://bugzilla.gnome.org/show_bug.cgi?id=563627. */ |
| 10726 | id = g_log_set_handler ("GLib", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL | 10722 | id = g_log_set_handler ("GLib", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL |
| @@ -11470,6 +11466,15 @@ x_initialize (void) | |||
| 11470 | XSetIOErrorHandler (x_io_error_quitter); | 11466 | XSetIOErrorHandler (x_io_error_quitter); |
| 11471 | } | 11467 | } |
| 11472 | 11468 | ||
| 11469 | #ifdef USE_GTK | ||
| 11470 | void | ||
| 11471 | init_xterm (void) | ||
| 11472 | { | ||
| 11473 | /* Emacs can handle only core input events, so make sure | ||
| 11474 | Gtk doesn't use Xinput or Xinput2 extensions. */ | ||
| 11475 | xputenv ("GDK_CORE_DEVICE_EVENTS=1"); | ||
| 11476 | } | ||
| 11477 | #endif | ||
| 11473 | 11478 | ||
| 11474 | void | 11479 | void |
| 11475 | syms_of_xterm (void) | 11480 | syms_of_xterm (void) |