summaryrefslogtreecommitdiff
path: root/src/sysdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sysdep.c')
-rw-r--r--src/sysdep.c286
1 files changed, 267 insertions, 19 deletions
diff --git a/src/sysdep.c b/src/sysdep.c
index ef2dc127e2a..cf2985b4b89 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -36,7 +36,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <utimens.h>
#include "lisp.h"
-#include "sheap.h"
#include "sysselect.h"
#include "blockinput.h"
@@ -134,6 +133,14 @@ int _cdecl _spawnlp (int, const char *, const char *, ...);
# include <sys/socket.h>
#endif
+#ifdef HAVE_ANDROID
+#include "android.h"
+#endif
+
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+#include "sfntfont.h"
+#endif
+
/* Declare here, including term.h is problematic on some systems. */
extern void tputs (const char *, int, int (*)(int));
@@ -252,7 +259,7 @@ init_standard_fds (void)
/* Set buferr if possible on platforms defining _PC_PIPE_BUF, as
they support the notion of atomic writes to pipes. */
#ifdef _PC_PIPE_BUF
- buferr = fdopen (STDERR_FILENO, "w");
+ buferr = emacs_fdopen (STDERR_FILENO, "w");
if (buferr)
setvbuf (buferr, NULL, _IOLBF, 0);
#endif
@@ -790,6 +797,7 @@ init_sigio (int fd)
#endif
}
+#ifndef HAVE_ANDROID
#ifndef DOS_NT
#ifdef F_SETOWN
static void
@@ -801,6 +809,7 @@ reset_sigio (int fd)
}
#endif /* F_SETOWN */
#endif
+#endif
void
request_sigio (void)
@@ -972,6 +981,8 @@ narrow_foreground_group (int fd)
tcsetpgrp_without_stopping (fd, getpid ());
}
+#ifndef HAVE_ANDROID
+
/* Set the tty to our original foreground group. */
static void
widen_foreground_group (int fd)
@@ -979,6 +990,9 @@ widen_foreground_group (int fd)
if (inherited_pgroup && setpgid (0, inherited_pgroup) == 0)
tcsetpgrp_without_stopping (fd, inherited_pgroup);
}
+
+#endif
+
/* Getting and setting emacs_tty structures. */
@@ -1496,6 +1510,8 @@ reset_sys_modes (struct tty_display_info *tty_out)
fflush (stdout);
return;
}
+
+#ifndef HAVE_ANDROID
if (!tty_out->term_initted)
return;
@@ -1552,6 +1568,7 @@ reset_sys_modes (struct tty_display_info *tty_out)
#endif
widen_foreground_group (fileno (tty_out->input));
+#endif
}
#ifdef HAVE_PTYS
@@ -1802,6 +1819,40 @@ handle_arith_signal (int sig)
xsignal0 (Qarith_error);
}
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY && defined HAVE_MMAP
+
+static void
+handle_sigbus (int sig, siginfo_t *siginfo, void *arg)
+{
+ /* If this arrives during sfntfont_open, then Emacs may be
+ screwed. */
+
+ if (sfntfont_detect_sigbus (siginfo->si_addr))
+ return;
+
+ handle_fatal_signal (sig);
+}
+
+/* Try to set up SIGBUS handling for the sfnt font driver.
+ Value is 1 upon failure, 0 otherwise. */
+
+static int
+init_sigbus (void)
+{
+ struct sigaction sa;
+
+ sigfillset (&sa.sa_mask);
+ sa.sa_sigaction = handle_sigbus;
+ sa.sa_flags = SA_SIGINFO;
+
+ if (sigaction (SIGBUS, &sa, NULL))
+ return 1;
+
+ return 0;
+}
+
+#endif
+
#if defined HAVE_STACK_OVERFLOW_HANDLING && !defined WINDOWSNT
/* Alternate stack used by SIGSEGV handler below. */
@@ -1866,6 +1917,8 @@ stack_overflow (siginfo_t *siginfo)
return 0 <= top - addr && top - addr < (bot - top) >> LG_STACK_HEURISTIC;
}
+/* Signal handler for SIGSEGV before our new handler was installed. */
+static struct sigaction old_sigsegv_handler;
/* Attempt to recover from SIGSEGV caused by C stack overflow. */
@@ -1884,6 +1937,15 @@ handle_sigsegv (int sig, siginfo_t *siginfo, void *arg)
if (!fatal && stack_overflow (siginfo))
siglongjmp (return_to_command_loop, 1);
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+ /* Tombstones (crash reports with stack traces) won't be generated on
+ Android unless the original SIGSEGV handler is installed and the
+ signal is resent, such as by returning from the first signal
+ handler called. */
+ sigaction (SIGSEGV, &old_sigsegv_handler, NULL);
+ return;
+#endif /* HAVE_ANDROID && ANDROID_STUBIFY */
+
/* Otherwise we can't do anything with this. */
deliver_fatal_thread_signal (sig);
}
@@ -1906,7 +1968,7 @@ init_sigsegv (void)
sigfillset (&sa.sa_mask);
sa.sa_sigaction = handle_sigsegv;
sa.sa_flags = SA_SIGINFO | SA_ONSTACK | emacs_sigaction_flags ();
- if (sigaction (SIGSEGV, &sa, NULL) < 0)
+ if (sigaction (SIGSEGV, &sa, &old_sigsegv_handler) < 0)
return 0;
return 1;
@@ -2027,12 +2089,17 @@ init_signals (void)
#endif /* __vax__ */
}
+ /* SIGUSR1 and SIGUSR2 are used internally by the android_select
+ function. */
+#if !defined HAVE_ANDROID
#ifdef SIGUSR1
add_user_signal (SIGUSR1, "sigusr1");
#endif
#ifdef SIGUSR2
add_user_signal (SIGUSR2, "sigusr2");
#endif
+#endif
+
sigaction (SIGABRT, &thread_fatal_action, 0);
#ifdef SIGPRE
sigaction (SIGPRE, &thread_fatal_action, 0);
@@ -2056,7 +2123,10 @@ init_signals (void)
sigaction (SIGEMT, &thread_fatal_action, 0);
#endif
#ifdef SIGBUS
- sigaction (SIGBUS, &thread_fatal_action, 0);
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY && defined HAVE_MMAP
+ if (init_sigbus ())
+#endif
+ sigaction (SIGBUS, &thread_fatal_action, 0);
#endif
if (!init_sigsegv ())
sigaction (SIGSEGV, &thread_fatal_action, 0);
@@ -2313,7 +2383,8 @@ emacs_backtrace (int backtrace_limit)
}
}
-#ifndef HAVE_NTGUI
+#if !defined HAVE_NTGUI && !(defined HAVE_ANDROID \
+ && !defined ANDROID_STUBIFY)
void
emacs_abort (void)
{
@@ -2335,11 +2406,20 @@ int
emacs_fstatat (int dirfd, char const *filename, void *st, int flags)
{
int r;
- while ((r = fstatat (dirfd, filename, st, flags)) != 0 && errno == EINTR)
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
+ while ((r = fstatat (dirfd, filename, st, flags)) != 0
+ && errno == EINTR)
+ maybe_quit ();
+#else
+ while ((r = android_fstatat (dirfd, filename, st, flags)) != 0
+ && errno == EINTR)
maybe_quit ();
+#endif
return r;
}
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
+
static int
sys_openat (int dirfd, char const *file, int oflags, int mode)
{
@@ -2354,6 +2434,28 @@ sys_openat (int dirfd, char const *file, int oflags, int mode)
#endif
}
+#endif
+
+int
+sys_fstat (int fd, struct stat *statb)
+{
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
+ return fstat (fd, statb);
+#else
+ return android_fstat (fd, statb);
+#endif
+}
+
+int
+sys_faccessat (int fd, const char *pathname, int mode, int flags)
+{
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
+ return faccessat (fd, pathname, mode, flags);
+#else
+ return android_faccessat (fd, pathname, mode, flags);
+#endif
+}
+
/* Assuming the directory DIRFD, open FILE for Emacs use,
using open flags OFLAGS and mode MODE.
Use binary I/O on systems that care about text vs binary I/O.
@@ -2362,6 +2464,8 @@ sys_openat (int dirfd, char const *file, int oflags, int mode)
Do not fail merely because the open was interrupted by a signal.
Allow the user to quit. */
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
+
int
emacs_openat (int dirfd, char const *file, int oflags, int mode)
{
@@ -2374,10 +2478,23 @@ emacs_openat (int dirfd, char const *file, int oflags, int mode)
return fd;
}
+#endif
+
int
emacs_open (char const *file, int oflags, int mode)
{
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+ int fd;
+#endif
+
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
return emacs_openat (AT_FDCWD, file, oflags, mode);
+#else
+ while ((fd = android_open (file, oflags, mode)) < 0 && errno == EINTR)
+ maybe_quit ();
+
+ return fd;
+#endif
}
/* Same as above, but doesn't allow the user to quit. */
@@ -2389,9 +2506,15 @@ emacs_open_noquit (char const *file, int oflags, int mode)
if (! (oflags & O_TEXT))
oflags |= O_BINARY;
oflags |= O_CLOEXEC;
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
do
fd = open (file, oflags, mode);
while (fd < 0 && errno == EINTR);
+#else
+ do
+ fd = android_open (file, oflags, mode);
+ while (fd < 0 && errno == EINTR);
+#endif
return fd;
}
@@ -2422,7 +2545,7 @@ emacs_fopen (char const *file, char const *mode)
}
fd = emacs_open (file, omode | oflags | bflag, 0666);
- return fd < 0 ? 0 : fdopen (fd, mode);
+ return fd < 0 ? 0 : emacs_fdopen (fd, mode);
}
/* Create a pipe for Emacs use. */
@@ -2441,6 +2564,8 @@ emacs_pipe (int fd[2])
For the background behind this mess, please see Austin Group defect 529
<https://austingroupbugs.net/view.php?id=529>. */
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
+
#ifndef POSIX_CLOSE_RESTART
# define POSIX_CLOSE_RESTART 1
static int
@@ -2467,6 +2592,8 @@ posix_close (int fd, int flag)
}
#endif
+#endif
+
/* Close FD, retrying if interrupted. If successful, return 0;
otherwise, return -1 and set errno to a non-EINTR value. Consider
an EINPROGRESS error to be successful, as that's merely a signal
@@ -2479,9 +2606,17 @@ posix_close (int fd, int flag)
int
emacs_close (int fd)
{
+ int r;
+
while (1)
{
- int r = posix_close (fd, POSIX_CLOSE_RESTART);
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
+ r = posix_close (fd, POSIX_CLOSE_RESTART);
+#else
+ r = android_close (fd) == 0 || errno == EINTR ? 0 : -1;
+#define POSIX_CLOSE_RESTART 1
+#endif
+
if (r == 0)
return r;
if (!POSIX_CLOSE_RESTART || errno != EINTR)
@@ -2492,6 +2627,106 @@ emacs_close (int fd)
}
}
+/* Wrapper around fdopen. On Android, this calls `android_fclose' to
+ clear information associated with FD if necessary. */
+
+FILE *
+emacs_fdopen (int fd, const char *mode)
+{
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
+ return fdopen (fd, mode);
+#else /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
+ return android_fdopen (fd, mode);
+#endif /* !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) */
+}
+
+/* Wrapper around fclose. On Android, this calls `android_fclose' to
+ clear information associated with the FILE's file descriptor if
+ necessary. */
+
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+int
+emacs_fclose (FILE *stream)
+{
+ return android_fclose (stream);
+}
+#endif
+
+/* Wrappers around unlink, symlink, rename, renameat_noreplace, and
+ rmdir. These operations handle asset and content directories on
+ Android, and may return EINTR. */
+
+int
+emacs_unlink (const char *name)
+{
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
+ return unlink (name);
+#else /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
+ return android_unlink (name);
+#endif /* !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) */
+}
+
+int
+emacs_symlink (const char *target, const char *linkname)
+{
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
+ return symlink (target, linkname);
+#else /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
+ return android_symlink (target, linkname);
+#endif /* !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) */
+}
+
+int
+emacs_rmdir (const char *dirname)
+{
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
+ return rmdir (dirname);
+#else /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
+ return android_rmdir (dirname);
+#endif /* !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) */
+}
+
+int
+emacs_mkdir (const char *dirname, mode_t mode)
+{
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
+ return mkdir (dirname, mode);
+#else /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
+ return android_mkdir (dirname, mode);
+#endif /* !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) */
+}
+
+int
+emacs_renameat_noreplace (int srcfd, const char *src,
+ int dstfd, const char *dst)
+{
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
+ return renameat_noreplace (srcfd, src, dstfd, dst);
+#else /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
+ return android_renameat_noreplace (srcfd, src, dstfd, dst);
+#endif /* !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) */
+}
+
+int
+emacs_rename (const char *src, const char *dst)
+{
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
+ return rename (src, dst);
+#else /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
+ return android_rename (src, dst);
+#endif /* !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) */
+}
+
+int
+emacs_fchmodat (int fd, const char *path, mode_t mode, int flags)
+{
+#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
+ return fchmodat (fd, path, mode, flags);
+#else /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
+ return android_fchmodat (fd, path, mode, flags);
+#endif /* !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) */
+}
+
/* Maximum number of bytes to read or write in a single system call.
This works around a serious bug in Linux kernels before 2.6.16; see
<https://bugzilla.redhat.com/show_bug.cgi?format=multiple&id=612839>.
@@ -2660,10 +2895,11 @@ emacs_perror (char const *message)
int
renameat_noreplace (int srcfd, char const *src, int dstfd, char const *dst)
{
-#if defined SYS_renameat2 && defined RENAME_NOREPLACE
- return syscall (SYS_renameat2, srcfd, src, dstfd, dst, RENAME_NOREPLACE);
-#elif defined CYGWIN && defined RENAME_NOREPLACE
+#if HAVE_RENAMEAT2 && defined RENAME_NOREPLACE
return renameat2 (srcfd, src, dstfd, dst, RENAME_NOREPLACE);
+#elif defined SYS_renameat2 && defined RENAME_NOREPLACE
+ /* Linux kernel 3.15 (2014) or later, with glibc 2.27 (2018) or earlier. */
+ return syscall (SYS_renameat2, srcfd, src, dstfd, dst, RENAME_NOREPLACE);
#elif defined RENAME_EXCL
return renameatx_np (srcfd, src, dstfd, dst, RENAME_EXCL);
#else
@@ -2735,6 +2971,17 @@ errwrite (void const *buf, ptrdiff_t nbuf)
void
close_output_streams (void)
{
+ /* Android comes with some kind of ``file descriptor sanitizer''
+ that aborts when stdout or stderr is closed. (bug#65340)
+
+ Perform this unconditionally as long as __ANDROID__ is defined,
+ since the file descriptor sanitizer also applies to regular TTY
+ builds under Android. */
+
+#ifdef __ANDROID__
+ fflush (stderr);
+ fflush (stdout);
+#else /* !__ANDROID__ */
if (close_stream (stdout) != 0)
{
emacs_perror ("Write error to standard output");
@@ -2748,6 +2995,7 @@ close_output_streams (void)
? fflush (stderr) != 0 || ferror (stderr)
: close_stream (stderr) != 0))
_exit (EXIT_FAILURE);
+#endif /* __ANDROID__ */
}
#ifndef DOS_NT
@@ -3204,7 +3452,7 @@ make_lisp_timeval (struct timeval t)
#endif
-#if defined (GNU_LINUX) || defined (CYGWIN)
+#if defined (GNU_LINUX) || defined (CYGWIN) || defined __ANDROID__
static Lisp_Object
time_from_jiffies (unsigned long long ticks, Lisp_Object hz, Lisp_Object form)
@@ -3245,14 +3493,14 @@ get_up_time (void)
Lisp_Object subsec = Fcons (make_fixnum (upfrac), make_fixnum (hz));
up = Ftime_add (sec, subsec);
}
- fclose (fup);
+ emacs_fclose (fup);
}
unblock_input ();
return up;
}
-# ifdef GNU_LINUX
+# if defined GNU_LINUX || defined __ANDROID__
#define MAJOR(d) (((unsigned)(d) >> 8) & 0xfff)
#define MINOR(d) (((unsigned)(d) & 0xff) | (((unsigned)(d) & 0xfff00000) >> 12))
@@ -3293,12 +3541,12 @@ procfs_ttyname (int rdev)
}
}
}
- fclose (fdev);
+ emacs_fclose (fdev);
}
unblock_input ();
return build_string (name);
}
-# endif /* GNU_LINUX */
+# endif /* GNU_LINUX || __ANDROID__ */
static uintmax_t
procfs_get_total_memory (void)
@@ -3335,7 +3583,7 @@ procfs_get_total_memory (void)
}
while (!done);
- fclose (fmem);
+ emacs_fclose (fmem);
}
unblock_input ();
return retval;
@@ -3447,9 +3695,9 @@ system_process_attributes (Lisp_Object pid)
attrs = Fcons (Fcons (Qppid, INT_TO_INTEGER (ppid)), attrs);
attrs = Fcons (Fcons (Qpgrp, INT_TO_INTEGER (pgrp)), attrs);
attrs = Fcons (Fcons (Qsess, INT_TO_INTEGER (sess)), attrs);
-# ifdef GNU_LINUX
+# if defined GNU_LINUX || defined __ANDROID__
attrs = Fcons (Fcons (Qttname, procfs_ttyname (tty)), attrs);
-# endif
+# endif /* GNU_LINUX || __ANDROID__ */
attrs = Fcons (Fcons (Qtpgid, INT_TO_INTEGER (tpgid)), attrs);
attrs = Fcons (Fcons (Qminflt, INT_TO_INTEGER (minflt)), attrs);
attrs = Fcons (Fcons (Qmajflt, INT_TO_INTEGER (majflt)), attrs);