summary refs log tree commit diff
path: root/sysdeps/posix
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2004-11-13 03:09:30 +0000
committerUlrich Drepper <drepper@redhat.com>2004-11-13 03:09:30 +0000
commit1327439fc6ef182c3ab8c69a55d3bee15b3c62a7 (patch)
treeb75895fb1606e0fa9c6e88399eaea669c192898d /sysdeps/posix
parentbfd259e0f6343422944a66a55d7432c2c9b1562e (diff)
downloadglibc-1327439fc6ef182c3ab8c69a55d3bee15b3c62a7.tar.gz
glibc-1327439fc6ef182c3ab8c69a55d3bee15b3c62a7.tar.xz
glibc-1327439fc6ef182c3ab8c69a55d3bee15b3c62a7.zip
Add new function __libc_message which performs the printing and simple format string handling. The string is written to tty, stderr, syslog in this order, stopping after the first successful output.
Diffstat (limited to 'sysdeps/posix')
-rw-r--r--sysdeps/posix/libc_fatal.c123
1 files changed, 104 insertions, 19 deletions
diff --git a/sysdeps/posix/libc_fatal.c b/sysdeps/posix/libc_fatal.c
index 7e45174708..fd97017579 100644
--- a/sysdeps/posix/libc_fatal.c
+++ b/sysdeps/posix/libc_fatal.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1994, 1995, 1997, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1993,1994,1995,1997,2000,2004 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
@@ -16,44 +16,129 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdarg.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sysdep.h>
 #include <string.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include <sys/syslog.h>
+#include <not-cancel.h>
 
 #ifdef FATAL_PREPARE_INCLUDE
 #include FATAL_PREPARE_INCLUDE
 #endif
 
+struct str_list
+{
+  const char *str;
+  size_t len;
+  struct str_list *next;
+};
+
+
 /* Abort with an error message.  */
 void
-__libc_fatal (message)
-     const char *message;
+__libc_message (int do_abort, const char *fmt, ...)
 {
-  size_t len = strlen (message);
+  va_list ap;
+  va_list ap_copy;
+  int fd = -1;
+
+  va_start (ap, fmt);
+  va_copy (ap_copy, ap);
 
 #ifdef FATAL_PREPARE
   FATAL_PREPARE;
 #endif
 
-  while (len > 0)
+  /* Open a descriptor for /dev/tty unless the user explicitly
+     requests errors on standard error.  */
+  const char *on_2 = __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')
     {
-      register int count = __write (STDERR_FILENO, message, len);
-      if (count > 0)
+      /* Find the next "%s" or the end of the string.  */
+      char *next = cp;
+      while (next[0] != '%' || next[1] != 's')
 	{
-	  message += count;
-	  len -= count;
+	  next = __strchrnul (next + 1, '%');
+
+	  if (next[0] == '\0')
+	    break;
 	}
-      else if (count < 0
-#ifdef EINTR
-	       && errno != EINTR
-#endif
-	       )
-	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 = list->str;
+	  iov[cnt].iov_len = list->len;
+	  total += list->len;
+	  list = list->next;
+	}
+
+      if (TEMP_FAILURE_RETRY (__writev (fd, iov, nlist)) == total)
+	written = true;
     }
 
-  abort ();
+  va_end (ap);
+
+  /* If we  had no success writing the message, use syslog.  */
+  if (! written)
+    vsyslog (LOG_ERR, fmt, ap_copy);
+
+  if (do_abort()
+      /* Kill the application.  */
+      abort ();
+}
+
+
+void
+__libc_fatal (message)
+     const char *message;
+{
+  __libc_message (1, "%s", message);
 }
 libc_hidden_def (__libc_fatal)