aboutsummaryrefslogtreecommitdiffstats
path: root/src/sysdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sysdep.c')
-rw-r--r--src/sysdep.c263
1 files changed, 191 insertions, 72 deletions
diff --git a/src/sysdep.c b/src/sysdep.c
index 212ceef64b9..f614d8bc557 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -22,7 +22,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
22#define SYSTIME_INLINE EXTERN_INLINE 22#define SYSTIME_INLINE EXTERN_INLINE
23 23
24#include <execinfo.h> 24#include <execinfo.h>
25#include <stdio.h> 25#include "sysstdio.h"
26#ifdef HAVE_PWD_H 26#ifdef HAVE_PWD_H
27#include <pwd.h> 27#include <pwd.h>
28#include <grp.h> 28#include <grp.h>
@@ -31,7 +31,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
31#include <unistd.h> 31#include <unistd.h>
32 32
33#include <c-ctype.h> 33#include <c-ctype.h>
34#include <ignore-value.h>
35#include <utimens.h> 34#include <utimens.h>
36 35
37#include "lisp.h" 36#include "lisp.h"
@@ -103,8 +102,8 @@ int _cdecl _getpid (void);
103#include "syssignal.h" 102#include "syssignal.h"
104#include "systime.h" 103#include "systime.h"
105 104
106static int emacs_get_tty (int, struct emacs_tty *); 105static void emacs_get_tty (int, struct emacs_tty *);
107static int emacs_set_tty (int, struct emacs_tty *, int); 106static int emacs_set_tty (int, struct emacs_tty *, bool);
108 107
109/* ULLONG_MAX is missing on Red Hat Linux 7.3; see Bug#11781. */ 108/* ULLONG_MAX is missing on Red Hat Linux 7.3; see Bug#11781. */
110#ifndef ULLONG_MAX 109#ifndef ULLONG_MAX
@@ -538,13 +537,11 @@ sys_subshell (void)
538 if (str && chdir ((char *) str) != 0) 537 if (str && chdir ((char *) str) != 0)
539 { 538 {
540#ifndef DOS_NT 539#ifndef DOS_NT
541 ignore_value (write (1, "Can't chdir\n", 12)); 540 emacs_perror ((char *) str);
542 _exit (1); 541 _exit (EXIT_CANCELED);
543#endif 542#endif
544 } 543 }
545 544
546 close_process_descs (); /* Close Emacs's pipes/ptys */
547
548#ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida */ 545#ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida */
549 { 546 {
550 char *epwd = getenv ("PWD"); 547 char *epwd = getenv ("PWD");
@@ -572,8 +569,8 @@ sys_subshell (void)
572 write (1, "Can't execute subshell", 22); 569 write (1, "Can't execute subshell", 22);
573#else /* not WINDOWSNT */ 570#else /* not WINDOWSNT */
574 execlp (sh, sh, (char *) 0); 571 execlp (sh, sh, (char *) 0);
575 ignore_value (write (1, "Can't execute subshell", 22)); 572 emacs_perror (sh);
576 _exit (1); 573 _exit (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
577#endif /* not WINDOWSNT */ 574#endif /* not WINDOWSNT */
578#endif /* not MSDOS */ 575#endif /* not MSDOS */
579 } 576 }
@@ -772,31 +769,26 @@ widen_foreground_group (int fd)
772 769
773/* Getting and setting emacs_tty structures. */ 770/* Getting and setting emacs_tty structures. */
774 771
775/* Set *TC to the parameters associated with the terminal FD. 772/* Set *TC to the parameters associated with the terminal FD,
776 Return zero if all's well, or -1 if we ran into an error we 773 or clear it if the parameters are not available. */
777 couldn't deal with. */ 774static void
778int
779emacs_get_tty (int fd, struct emacs_tty *settings) 775emacs_get_tty (int fd, struct emacs_tty *settings)
780{ 776{
781 /* Retrieve the primary parameters - baud rate, character size, etcetera. */ 777 /* Retrieve the primary parameters - baud rate, character size, etcetera. */
782#ifndef DOS_NT 778#ifndef DOS_NT
783 /* We have those nifty POSIX tcmumbleattr functions. */ 779 /* We have those nifty POSIX tcmumbleattr functions. */
784 memset (&settings->main, 0, sizeof (settings->main)); 780 memset (&settings->main, 0, sizeof (settings->main));
785 if (tcgetattr (fd, &settings->main) < 0) 781 tcgetattr (fd, &settings->main);
786 return -1;
787#endif 782#endif
788
789 /* We have survived the tempest. */
790 return 0;
791} 783}
792 784
793 785
794/* Set the parameters of the tty on FD according to the contents of 786/* Set the parameters of the tty on FD according to the contents of
795 *SETTINGS. If FLUSHP is non-zero, we discard input. 787 *SETTINGS. If FLUSHP, discard input.
796 Return 0 if all went well, and -1 if anything failed. */ 788 Return 0 if all went well, and -1 (setting errno) if anything failed. */
797 789
798int 790static int
799emacs_set_tty (int fd, struct emacs_tty *settings, int flushp) 791emacs_set_tty (int fd, struct emacs_tty *settings, bool flushp)
800{ 792{
801 /* Set the primary parameters - baud rate, character size, etcetera. */ 793 /* Set the primary parameters - baud rate, character size, etcetera. */
802#ifndef DOS_NT 794#ifndef DOS_NT
@@ -1121,10 +1113,10 @@ init_sys_modes (struct tty_display_info *tty_out)
1121 tty_out->term_initted = 1; 1113 tty_out->term_initted = 1;
1122} 1114}
1123 1115
1124/* Return nonzero if safe to use tabs in output. 1116/* Return true if safe to use tabs in output.
1125 At the time this is called, init_sys_modes has not been done yet. */ 1117 At the time this is called, init_sys_modes has not been done yet. */
1126 1118
1127int 1119bool
1128tabs_safe_p (int fd) 1120tabs_safe_p (int fd)
1129{ 1121{
1130 struct emacs_tty etty; 1122 struct emacs_tty etty;
@@ -1378,8 +1370,10 @@ init_system_name (void)
1378 uname (&uts); 1370 uname (&uts);
1379 Vsystem_name = build_string (uts.nodename); 1371 Vsystem_name = build_string (uts.nodename);
1380#else /* HAVE_GETHOSTNAME */ 1372#else /* HAVE_GETHOSTNAME */
1381 unsigned int hostname_size = 256; 1373 char *hostname_alloc = NULL;
1382 char *hostname = alloca (hostname_size); 1374 char hostname_buf[256];
1375 ptrdiff_t hostname_size = sizeof hostname_buf;
1376 char *hostname = hostname_buf;
1383 1377
1384 /* Try to get the host name; if the buffer is too short, try 1378 /* Try to get the host name; if the buffer is too short, try
1385 again. Apparently, the only indication gethostname gives of 1379 again. Apparently, the only indication gethostname gives of
@@ -1394,8 +1388,8 @@ init_system_name (void)
1394 if (strlen (hostname) < hostname_size - 1) 1388 if (strlen (hostname) < hostname_size - 1)
1395 break; 1389 break;
1396 1390
1397 hostname_size <<= 1; 1391 hostname = hostname_alloc = xpalloc (hostname_alloc, &hostname_size, 1,
1398 hostname = alloca (hostname_size); 1392 min (PTRDIFF_MAX, SIZE_MAX), 1);
1399 } 1393 }
1400#ifdef HAVE_SOCKETS 1394#ifdef HAVE_SOCKETS
1401 /* Turn the hostname into the official, fully-qualified hostname. 1395 /* Turn the hostname into the official, fully-qualified hostname.
@@ -1440,7 +1434,13 @@ init_system_name (void)
1440 } 1434 }
1441 if (it) 1435 if (it)
1442 { 1436 {
1443 hostname = alloca (strlen (it->ai_canonname) + 1); 1437 ptrdiff_t len = strlen (it->ai_canonname);
1438 if (hostname_size <= len)
1439 {
1440 hostname_size = len + 1;
1441 hostname = hostname_alloc = xrealloc (hostname_alloc,
1442 hostname_size);
1443 }
1444 strcpy (hostname, it->ai_canonname); 1444 strcpy (hostname, it->ai_canonname);
1445 } 1445 }
1446 freeaddrinfo (res); 1446 freeaddrinfo (res);
@@ -1487,10 +1487,11 @@ init_system_name (void)
1487 } 1487 }
1488#endif /* HAVE_SOCKETS */ 1488#endif /* HAVE_SOCKETS */
1489 Vsystem_name = build_string (hostname); 1489 Vsystem_name = build_string (hostname);
1490 xfree (hostname_alloc);
1490#endif /* HAVE_GETHOSTNAME */ 1491#endif /* HAVE_GETHOSTNAME */
1491 { 1492 {
1492 unsigned char *p; 1493 char *p;
1493 for (p = SDATA (Vsystem_name); *p; p++) 1494 for (p = SSDATA (Vsystem_name); *p; p++)
1494 if (*p == ' ' || *p == '\t') 1495 if (*p == ' ' || *p == '\t')
1495 *p = '-'; 1496 *p = '-';
1496 } 1497 }
@@ -1630,7 +1631,7 @@ deliver_thread_signal (int sig, signal_handler_t handler)
1630# undef sys_siglist 1631# undef sys_siglist
1631# ifdef _sys_siglist 1632# ifdef _sys_siglist
1632# define sys_siglist _sys_siglist 1633# define sys_siglist _sys_siglist
1633# elif defined HAVE_DECL___SYS_SIGLIST 1634# elif HAVE_DECL___SYS_SIGLIST
1634# define sys_siglist __sys_siglist 1635# define sys_siglist __sys_siglist
1635# else 1636# else
1636# define sys_siglist my_sys_siglist 1637# define sys_siglist my_sys_siglist
@@ -2136,10 +2137,10 @@ emacs_backtrace (int backtrace_limit)
2136 2137
2137 if (npointers) 2138 if (npointers)
2138 { 2139 {
2139 ignore_value (write (STDERR_FILENO, "\nBacktrace:\n", 12)); 2140 emacs_write (STDERR_FILENO, "\nBacktrace:\n", 12);
2140 backtrace_symbols_fd (buffer, npointers, STDERR_FILENO); 2141 backtrace_symbols_fd (buffer, npointers, STDERR_FILENO);
2141 if (bounded_limit < npointers) 2142 if (bounded_limit < npointers)
2142 ignore_value (write (STDERR_FILENO, "...\n", 4)); 2143 emacs_write (STDERR_FILENO, "...\n", 4);
2143 } 2144 }
2144} 2145}
2145 2146
@@ -2151,34 +2152,108 @@ emacs_abort (void)
2151} 2152}
2152#endif 2153#endif
2153 2154
2155/* Open FILE for Emacs use, using open flags OFLAG and mode MODE.
2156 Arrange for subprograms to not inherit the file descriptor.
2157 Prefer a method that is multithread-safe, if available.
2158 Do not fail merely because the open was interrupted by a signal.
2159 Allow the user to quit. */
2160
2154int 2161int
2155emacs_open (const char *path, int oflag, int mode) 2162emacs_open (const char *file, int oflags, int mode)
2156{ 2163{
2157 register int rtnval; 2164 int fd;
2158 2165 oflags |= O_CLOEXEC;
2159 while ((rtnval = open (path, oflag, mode)) == -1 2166 while ((fd = open (file, oflags, mode)) < 0 && errno == EINTR)
2160 && (errno == EINTR))
2161 QUIT; 2167 QUIT;
2162 return (rtnval); 2168 if (! O_CLOEXEC && 0 <= fd)
2169 fcntl (fd, F_SETFD, FD_CLOEXEC);
2170 return fd;
2163} 2171}
2164 2172
2165int 2173/* Open FILE as a stream for Emacs use, with mode MODE.
2166emacs_close (int fd) 2174 Act like emacs_open with respect to threads, signals, and quits. */
2175
2176FILE *
2177emacs_fopen (char const *file, char const *mode)
2167{ 2178{
2168 int did_retry = 0; 2179 int fd, omode, oflags;
2169 register int rtnval; 2180 int bflag = 0;
2181 char const *m = mode;
2170 2182
2171 while ((rtnval = close (fd)) == -1 2183 switch (*m++)
2172 && (errno == EINTR)) 2184 {
2173 did_retry = 1; 2185 case 'r': omode = O_RDONLY; oflags = 0; break;
2186 case 'w': omode = O_WRONLY; oflags = O_CREAT | O_TRUNC; break;
2187 case 'a': omode = O_WRONLY; oflags = O_CREAT | O_APPEND; break;
2188 default: emacs_abort ();
2189 }
2174 2190
2175 /* If close is interrupted SunOS 4.1 may or may not have closed the 2191 while (*m)
2176 file descriptor. If it did the second close will fail with 2192 switch (*m++)
2177 errno = EBADF. That means we have succeeded. */ 2193 {
2178 if (rtnval == -1 && did_retry && errno == EBADF) 2194 case '+': omode = O_RDWR; break;
2179 return 0; 2195 case 'b': bflag = O_BINARY; break;
2196 case 't': bflag = O_TEXT; break;
2197 default: /* Ignore. */ break;
2198 }
2199
2200 fd = emacs_open (file, omode | oflags | bflag, 0666);
2201 return fd < 0 ? 0 : fdopen (fd, mode);
2202}
2203
2204/* Approximate posix_close and POSIX_CLOSE_RESTART well enough for Emacs.
2205 For the background behind this mess, please see Austin Group defect 529
2206 <http://austingroupbugs.net/view.php?id=529>. */
2207
2208#ifndef POSIX_CLOSE_RESTART
2209# define POSIX_CLOSE_RESTART 1
2210static int
2211posix_close (int fd, int flag)
2212{
2213 /* Only the POSIX_CLOSE_RESTART case is emulated. */
2214 eassert (flag == POSIX_CLOSE_RESTART);
2180 2215
2181 return rtnval; 2216 /* Things are tricky if close (fd) returns -1 with errno == EINTR
2217 on a system that does not define POSIX_CLOSE_RESTART.
2218
2219 In this case, in some systems (e.g., GNU/Linux, AIX) FD is
2220 closed, and retrying the close could inadvertently close a file
2221 descriptor allocated by some other thread. In other systems
2222 (e.g., HP/UX) FD is not closed. And in still other systems
2223 (e.g., OS X, Solaris), maybe FD is closed, maybe not, and in a
2224 multithreaded program there can be no way to tell.
2225
2226 So, in this case, pretend that the close succeeded. This works
2227 well on systems like GNU/Linux that close FD. Although it may
2228 leak a file descriptor on other systems, the leak is unlikely and
2229 it's better to leak than to close a random victim. */
2230 return close (fd) == 0 || errno == EINTR ? 0 : -1;
2231}
2232#endif
2233
2234/* Close FD, retrying if interrupted. If successful, return 0;
2235 otherwise, return -1 and set errno to a non-EINTR value. Consider
2236 an EINPROGRESS error to be successful, as that's merely a signal
2237 arriving. FD is always closed when this function returns, even
2238 when it returns -1.
2239
2240 Do not call this function if FD is nonnegative and might already be closed,
2241 as that might close an innocent victim opened by some other thread. */
2242
2243int
2244emacs_close (int fd)
2245{
2246 while (1)
2247 {
2248 int r = posix_close (fd, POSIX_CLOSE_RESTART);
2249 if (r == 0)
2250 return r;
2251 if (!POSIX_CLOSE_RESTART || errno != EINTR)
2252 {
2253 eassert (errno != EBADF || fd < 0);
2254 return errno == EINPROGRESS ? 0 : r;
2255 }
2256 }
2182} 2257}
2183 2258
2184/* Maximum number of bytes to read or write in a single system call. 2259/* Maximum number of bytes to read or write in a single system call.
@@ -2210,27 +2285,26 @@ emacs_read (int fildes, char *buf, ptrdiff_t nbyte)
2210} 2285}
2211 2286
2212/* Write to FILEDES from a buffer BUF with size NBYTE, retrying if interrupted 2287/* Write to FILEDES from a buffer BUF with size NBYTE, retrying if interrupted
2213 or if a partial write occurs. Return the number of bytes written, setting 2288 or if a partial write occurs. If interrupted, process pending
2289 signals if PROCESS SIGNALS. Return the number of bytes written, setting
2214 errno if this is less than NBYTE. */ 2290 errno if this is less than NBYTE. */
2215ptrdiff_t 2291static ptrdiff_t
2216emacs_write (int fildes, const char *buf, ptrdiff_t nbyte) 2292emacs_full_write (int fildes, char const *buf, ptrdiff_t nbyte,
2293 bool process_signals)
2217{ 2294{
2218 ssize_t rtnval; 2295 ptrdiff_t bytes_written = 0;
2219 ptrdiff_t bytes_written;
2220
2221 bytes_written = 0;
2222 2296
2223 while (nbyte > 0) 2297 while (nbyte > 0)
2224 { 2298 {
2225 rtnval = write (fildes, buf, min (nbyte, MAX_RW_COUNT)); 2299 ssize_t n = write (fildes, buf, min (nbyte, MAX_RW_COUNT));
2226 2300
2227 if (rtnval < 0) 2301 if (n < 0)
2228 { 2302 {
2229 if (errno == EINTR) 2303 if (errno == EINTR)
2230 { 2304 {
2231 /* I originally used `QUIT' but that might causes files to 2305 /* I originally used `QUIT' but that might causes files to
2232 be truncated if you hit C-g in the middle of it. --Stef */ 2306 be truncated if you hit C-g in the middle of it. --Stef */
2233 if (pending_signals) 2307 if (process_signals && pending_signals)
2234 process_pending_signals (); 2308 process_pending_signals ();
2235 continue; 2309 continue;
2236 } 2310 }
@@ -2238,12 +2312,57 @@ emacs_write (int fildes, const char *buf, ptrdiff_t nbyte)
2238 break; 2312 break;
2239 } 2313 }
2240 2314
2241 buf += rtnval; 2315 buf += n;
2242 nbyte -= rtnval; 2316 nbyte -= n;
2243 bytes_written += rtnval; 2317 bytes_written += n;
2244 } 2318 }
2245 2319
2246 return (bytes_written); 2320 return bytes_written;
2321}
2322
2323/* Write to FILEDES from a buffer BUF with size NBYTE, retrying if
2324 interrupted or if a partial write occurs. Return the number of
2325 bytes written, setting errno if this is less than NBYTE. */
2326ptrdiff_t
2327emacs_write (int fildes, char const *buf, ptrdiff_t nbyte)
2328{
2329 return emacs_full_write (fildes, buf, nbyte, 0);
2330}
2331
2332/* Like emacs_write, but also process pending signals if interrupted. */
2333ptrdiff_t
2334emacs_write_sig (int fildes, char const *buf, ptrdiff_t nbyte)
2335{
2336 return emacs_full_write (fildes, buf, nbyte, 1);
2337}
2338
2339/* Write a diagnostic to standard error that contains MESSAGE and a
2340 string derived from errno. Preserve errno. Do not buffer stderr.
2341 Do not process pending signals if interrupted. */
2342void
2343emacs_perror (char const *message)
2344{
2345 int err = errno;
2346 char const *error_string = strerror (err);
2347 char const *command = (initial_argv && initial_argv[0]
2348 ? initial_argv[0] : "emacs");
2349 /* Write it out all at once, if it's short; this is less likely to
2350 be interleaved with other output. */
2351 char buf[BUFSIZ];
2352 int nbytes = snprintf (buf, sizeof buf, "%s: %s: %s\n",
2353 command, message, error_string);
2354 if (0 <= nbytes && nbytes < BUFSIZ)
2355 emacs_write (STDERR_FILENO, buf, nbytes);
2356 else
2357 {
2358 emacs_write (STDERR_FILENO, command, strlen (command));
2359 emacs_write (STDERR_FILENO, ": ", 2);
2360 emacs_write (STDERR_FILENO, message, strlen (message));
2361 emacs_write (STDERR_FILENO, ": ", 2);
2362 emacs_write (STDERR_FILENO, error_string, strlen (error_string));
2363 emacs_write (STDERR_FILENO, "\n", 1);
2364 }
2365 errno = err;
2247} 2366}
2248 2367
2249/* Return a struct timeval that is roughly equivalent to T. 2368/* Return a struct timeval that is roughly equivalent to T.
@@ -2597,7 +2716,7 @@ list_system_processes (void)
2597 2716
2598#endif /* !defined (WINDOWSNT) */ 2717#endif /* !defined (WINDOWSNT) */
2599 2718
2600#ifdef GNU_LINUX 2719#if defined GNU_LINUX && defined HAVE_LONG_LONG_INT
2601static EMACS_TIME 2720static EMACS_TIME
2602time_from_jiffies (unsigned long long tval, long hz) 2721time_from_jiffies (unsigned long long tval, long hz)
2603{ 2722{
@@ -2637,7 +2756,7 @@ get_up_time (void)
2637 EMACS_TIME up = make_emacs_time (0, 0); 2756 EMACS_TIME up = make_emacs_time (0, 0);
2638 2757
2639 block_input (); 2758 block_input ();
2640 fup = fopen ("/proc/uptime", "r"); 2759 fup = emacs_fopen ("/proc/uptime", "r");
2641 2760
2642 if (fup) 2761 if (fup)
2643 { 2762 {
@@ -2682,7 +2801,7 @@ procfs_ttyname (int rdev)
2682 char name[PATH_MAX]; 2801 char name[PATH_MAX];
2683 2802
2684 block_input (); 2803 block_input ();
2685 fdev = fopen ("/proc/tty/drivers", "r"); 2804 fdev = emacs_fopen ("/proc/tty/drivers", "r");
2686 2805
2687 if (fdev) 2806 if (fdev)
2688 { 2807 {
@@ -2724,7 +2843,7 @@ procfs_get_total_memory (void)
2724 unsigned long retval = 2 * 1024 * 1024; /* default: 2GB */ 2843 unsigned long retval = 2 * 1024 * 1024; /* default: 2GB */
2725 2844
2726 block_input (); 2845 block_input ();
2727 fmem = fopen ("/proc/meminfo", "r"); 2846 fmem = emacs_fopen ("/proc/meminfo", "r");
2728 2847
2729 if (fmem) 2848 if (fmem)
2730 { 2849 {