about summary refs log tree commit diff
path: root/REORG.TODO/sysdeps/posix/libc_fatal.c
diff options
context:
space:
mode:
Diffstat (limited to 'REORG.TODO/sysdeps/posix/libc_fatal.c')
-rw-r--r--REORG.TODO/sysdeps/posix/libc_fatal.c187
1 files changed, 187 insertions, 0 deletions
diff --git a/REORG.TODO/sysdeps/posix/libc_fatal.c b/REORG.TODO/sysdeps/posix/libc_fatal.c
new file mode 100644
index 0000000000..b261963679
--- /dev/null
+++ b/REORG.TODO/sysdeps/posix/libc_fatal.c
@@ -0,0 +1,187 @@
+/* Catastrophic failure reports.  Generic POSIX.1 version.
+   Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <atomic.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ldsodefs.h>
+#include <paths.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/uio.h>
+#include <not-cancel.h>
+
+#ifdef FATAL_PREPARE_INCLUDE
+#include FATAL_PREPARE_INCLUDE
+#endif
+
+#ifndef WRITEV_FOR_FATAL
+# define WRITEV_FOR_FATAL	writev_for_fatal
+static bool
+writev_for_fatal (int fd, const struct iovec *iov, size_t niov, size_t total)
+{
+  return TEMP_FAILURE_RETRY (__writev (fd, iov, niov)) == total;
+}
+#endif
+
+#ifndef BEFORE_ABORT
+# define BEFORE_ABORT		before_abort
+static void
+before_abort (int do_abort __attribute__ ((unused)),
+              bool written __attribute__ ((unused)),
+              int fd __attribute__ ((unused)))
+{
+}
+#endif
+
+struct str_list
+{
+  const char *str;
+  size_t len;
+  struct str_list *next;
+};
+
+/* Abort with an error message.  */
+void
+__libc_message (int do_abort, const char *fmt, ...)
+{
+  va_list ap;
+  int fd = -1;
+
+  va_start (ap, fmt);
+
+#ifdef FATAL_PREPARE
+  FATAL_PREPARE;
+#endif
+
+  /* Open a descriptor for /dev/tty unless the user explicitly
+     requests errors on standard error.  */
+  const char *on_2 = __libc_secure_getenv ("LIBC_FATAL_STDERR_");
+  if (on_2 == NULL || *on_2 == '\0')
+    fd = open_not_cancel_2 (_PATH_TTY, O_RDWR | O_NOCTTY | O_NDELAY);
+
+  if (fd == -1)
+    fd = STDERR_FILENO;
+
+  struct str_list *list = NULL;
+  int nlist = 0;
+
+  const char *cp = fmt;
+  while (*cp != '\0')
+    {
+      /* Find the next "%s" or the end of the string.  */
+      const char *next = cp;
+      while (next[0] != '%' || next[1] != 's')
+	{
+	  next = __strchrnul (next + 1, '%');
+
+	  if (next[0] == '\0')
+	    break;
+	}
+
+      /* Determine what to print.  */
+      const char *str;
+      size_t len;
+      if (cp[0] == '%' && cp[1] == 's')
+	{
+	  str = va_arg (ap, const char *);
+	  len = strlen (str);
+	  cp += 2;
+	}
+      else
+	{
+	  str = cp;
+	  len = next - cp;
+	  cp = next;
+	}
+
+      struct str_list *newp = alloca (sizeof (struct str_list));
+      newp->str = str;
+      newp->len = len;
+      newp->next = list;
+      list = newp;
+      ++nlist;
+    }
+
+  bool written = false;
+  if (nlist > 0)
+    {
+      struct iovec *iov = alloca (nlist * sizeof (struct iovec));
+      ssize_t total = 0;
+
+      for (int cnt = nlist - 1; cnt >= 0; --cnt)
+	{
+	  iov[cnt].iov_base = (char *) list->str;
+	  iov[cnt].iov_len = list->len;
+	  total += list->len;
+	  list = list->next;
+	}
+
+      written = WRITEV_FOR_FATAL (fd, iov, nlist, total);
+
+      if (do_abort)
+	{
+	  total = ((total + 1 + GLRO(dl_pagesize) - 1)
+		   & ~(GLRO(dl_pagesize) - 1));
+	  struct abort_msg_s *buf = __mmap (NULL, total,
+					    PROT_READ | PROT_WRITE,
+					    MAP_ANON | MAP_PRIVATE, -1, 0);
+	  if (__glibc_likely (buf != MAP_FAILED))
+	    {
+	      buf->size = total;
+	      char *wp = buf->msg;
+	      for (int cnt = 0; cnt < nlist; ++cnt)
+		wp = mempcpy (wp, iov[cnt].iov_base, iov[cnt].iov_len);
+	      *wp = '\0';
+
+	      /* We have to free the old buffer since the application might
+		 catch the SIGABRT signal.  */
+	      struct abort_msg_s *old = atomic_exchange_acq (&__abort_msg,
+							     buf);
+	      if (old != NULL)
+		__munmap (old, old->size);
+	    }
+	}
+    }
+
+  va_end (ap);
+
+  if (do_abort)
+    {
+      BEFORE_ABORT (do_abort, written, fd);
+
+      /* Kill the application.  */
+      abort ();
+    }
+}
+
+
+void
+__libc_fatal (const char *message)
+{
+  /* The loop is added only to keep gcc happy.  */
+  while (1)
+    __libc_message (1, "%s", message);
+}
+libc_hidden_def (__libc_fatal)