2005-07-26 Jakub Jelinek <jakub@redhat.com>
[kopensolaris-gnu/glibc.git] / misc / error.c
index aa0d8bb..34d92e0 100644 (file)
@@ -1,7 +1,6 @@
 /* Error handler for noninteractive utilities
-   Copyright (C) 1990-1998, 2000, 2001 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.  Its master source is NOT part of
-   the C library, however.  The master source lives in /gd/gnu/lib.
+   Copyright (C) 1990-1998, 2000-2004, 2005 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
@@ -74,6 +73,8 @@ unsigned int error_message_count;
 
 # define program_name program_invocation_name
 # include <errno.h>
+# include <limits.h>
+# include <libio/libioP.h>
 
 /* In GNU libc we want do not want to use the common name `error' directly.
    Instead make it a weak alias.  */
@@ -86,28 +87,39 @@ extern void __error_at_line (int status, int errnum, const char *file_name,
 # define error __error
 # define error_at_line __error_at_line
 
-# ifdef USE_IN_LIBIO
 # include <libio/iolibio.h>
-#  define fflush(s) _IO_fflush (s)
-# endif
+# define fflush(s) INTUSE(_IO_fflush) (s)
+# undef putc
+# define putc(c, fp) INTUSE(_IO_putc) (c, fp)
+
+# include <bits/libc-lock.h>
 
 #else /* not _LIBC */
 
+# if !HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P
+#  ifndef HAVE_DECL_STRERROR_R
+"this configure-time declaration test was not run"
+#  endif
+char *strerror_r ();
+# endif
+
 /* The calling program should define program_name and set it to the
    name of the executing program.  */
 extern char *program_name;
 
-# ifdef HAVE_STRERROR_R
+# if HAVE_STRERROR_R || defined strerror_r
 #  define __strerror_r strerror_r
 # else
 #  if HAVE_STRERROR
-#   ifndef strerror            /* On some systems, strerror is a macro */
+#   ifndef HAVE_DECL_STRERROR
+"this configure-time declaration test was not run"
+#   endif
+#   if !HAVE_DECL_STRERROR
 char *strerror ();
 #   endif
 #  else
 static char *
-private_strerror (errnum)
-     int errnum;
+private_strerror (int errnum)
 {
   extern char *sys_errlist[];
   extern int sys_nerr;
@@ -118,16 +130,46 @@ private_strerror (errnum)
 }
 #   define strerror private_strerror
 #  endif /* HAVE_STRERROR */
-# endif        /* HAVE_STRERROR_R */
+# endif        /* HAVE_STRERROR_R || defined strerror_r */
 #endif /* not _LIBC */
 
+static void
+print_errno_message (int errnum)
+{
+  char const *s;
+
+#if defined HAVE_STRERROR_R || _LIBC
+  char errbuf[1024];
+# if STRERROR_R_CHAR_P || _LIBC
+  s = __strerror_r (errnum, errbuf, sizeof errbuf);
+# else
+  if (__strerror_r (errnum, errbuf, sizeof errbuf) == 0)
+    s = errbuf;
+  else
+    s = 0;
+# endif
+#else
+  s = strerror (errnum);
+#endif
+
+#if !_LIBC
+  if (! s)
+    s = _("Unknown system error");
+#endif
+
+#if _LIBC
+  __fxprintf (NULL, ": %s", s);
+#else
+  fprintf (stderr, ": %s", s);
+#endif
+}
 
 #ifdef VA_START
 static void
 error_tail (int status, int errnum, const char *message, va_list args)
 {
 # if HAVE_VPRINTF || _LIBC
-#  if _LIBC && USE_IN_LIBIO
+#  if _LIBC
   if (_IO_fwide (stderr, 0) > 0)
     {
 #   define ALLOCA_LIMIT        2000
@@ -136,36 +178,58 @@ error_tail (int status, int errnum, const char *message, va_list args)
       mbstate_t st;
       size_t res;
       const char *tmp;
+      bool use_malloc = false;
 
-      do
+      while (1)
        {
-         if (len < ALLOCA_LIMIT)
+         if (__libc_use_alloca (len * sizeof (wchar_t)))
            wmessage = (wchar_t *) alloca (len * sizeof (wchar_t));
          else
            {
-             if (wmessage != NULL && len / 2 < ALLOCA_LIMIT)
+             if (!use_malloc)
                wmessage = NULL;
 
-             wmessage = (wchar_t *) realloc (wmessage,
-                                             len * sizeof (wchar_t));
-
-             if (wmessage == NULL)
+             wchar_t *p = (wchar_t *) realloc (wmessage,
+                                               len * sizeof (wchar_t));
+             if (p == NULL)
                {
+                 free (wmessage);
                  fputws_unlocked (L"out of memory\n", stderr);
                  return;
                }
+             wmessage = p;
+             use_malloc = true;
            }
 
          memset (&st, '\0', sizeof (st));
-         tmp =message;
+         tmp = message;
+
+         res = mbsrtowcs (wmessage, &tmp, len, &st);
+         if (res != len)
+           break;
+
+         if (__builtin_expect (len >= SIZE_MAX / 2, 0))
+           {
+             /* This really should not happen if everything is fine.  */
+             res = (size_t) -1;
+             break;
+           }
+
+         len *= 2;
        }
-      while ((res = mbsrtowcs (wmessage, &tmp, len, &st)) == len);
 
       if (res == (size_t) -1)
-       /* The string cannot be converted.  */
-       wmessage = (wchar_t *) L"???";
+       {
+         /* The string cannot be converted.  */
+         if (use_malloc)
+           free (wmessage);
+         wmessage = (wchar_t *) L"???";
+       }
 
       __vfwprintf (stderr, wmessage, args);
+
+      if (use_malloc)
+       free (wmessage);
     }
   else
 #  endif
@@ -177,26 +241,12 @@ error_tail (int status, int errnum, const char *message, va_list args)
 
   ++error_message_count;
   if (errnum)
-    {
-#if defined HAVE_STRERROR_R || _LIBC
-      char errbuf[1024];
-      char *s = __strerror_r (errnum, errbuf, sizeof errbuf);
-# if _LIBC && USE_IN_LIBIO
-      if (_IO_fwide (stderr, 0) > 0)
-       __fwprintf (stderr, L": %s", s);
-      else
+    print_errno_message (errnum);
+# if _LIBC
+  __fxprintf (NULL, "\n");
+# else
+  putc ('\n', stderr);
 # endif
-       fprintf (stderr, ": %s", s);
-#else
-      fprintf (stderr, ": %s", strerror (errnum));
-#endif
-    }
-#if _LIBC && USE_IN_LIBIO
-  if (_IO_fwide (stderr, 0) > 0)
-    putwc (L'\n', stderr);
-  else
-#endif
-    putc ('\n', stderr);
   fflush (stderr);
   if (status)
     exit (status);
@@ -224,24 +274,27 @@ error (status, errnum, message, va_alist)
   va_list args;
 #endif
 
+#if defined _LIBC && defined __libc_ptf_call
+  /* We do not want this call to be cut short by a thread
+     cancellation.  Therefore disable cancellation for now.  */
+  int state = PTHREAD_CANCEL_ENABLE;
+  __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state),
+                  0);
+#endif
+
   fflush (stdout);
 #ifdef _LIBC
-# ifdef USE_IN_LIBIO
   _IO_flockfile (stderr);
-# else
-  __flockfile (stderr);
-# endif
 #endif
   if (error_print_progname)
     (*error_print_progname) ();
   else
     {
-#if _LIBC && USE_IN_LIBIO
-      if (_IO_fwide (stderr, 0) > 0)
-       __fwprintf (stderr, L"%s: ", program_name);
-      else
+#if _LIBC
+      __fxprintf (NULL, "%s: ", program_name);
+#else
+      fprintf (stderr, "%s: ", program_name);
 #endif
-       fprintf (stderr, "%s: ", program_name);
     }
 
 #ifdef VA_START
@@ -252,7 +305,7 @@ error (status, errnum, message, va_alist)
 
   ++error_message_count;
   if (errnum)
-    fprintf (stderr, ": %s", strerror (errnum));
+    print_errno_message (errnum);
   putc ('\n', stderr);
   fflush (stderr);
   if (status)
@@ -260,10 +313,9 @@ error (status, errnum, message, va_alist)
 #endif
 
 #ifdef _LIBC
-# ifdef USE_IN_LIBIO
   _IO_funlockfile (stderr);
-# else
-  __funlockfile (stderr);
+# ifdef __libc_ptf_call
+  __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
 # endif
 #endif
 }
@@ -305,34 +357,36 @@ error_at_line (status, errnum, file_name, line_number, message, va_alist)
       old_line_number = line_number;
     }
 
+#if defined _LIBC && defined __libc_ptf_call
+  /* We do not want this call to be cut short by a thread
+     cancellation.  Therefore disable cancellation for now.  */
+  int state = PTHREAD_CANCEL_ENABLE;
+  __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state),
+                  0);
+#endif
+
   fflush (stdout);
 #ifdef _LIBC
-# ifdef USE_IN_LIBIO
   _IO_flockfile (stderr);
-# else
-  __flockfile (stderr);
-# endif
 #endif
   if (error_print_progname)
     (*error_print_progname) ();
   else
     {
-#if _LIBC && USE_IN_LIBIO
-      if (_IO_fwide (stderr, 0) > 0)
-       __fwprintf (stderr, L"%s: ", program_name);
-      else
+#if _LIBC
+      __fxprintf (NULL, "%s:", program_name);
+#else
+      fprintf (stderr, "%s:", program_name);
 #endif
-       fprintf (stderr, "%s:", program_name);
     }
 
   if (file_name != NULL)
     {
-#if _LIBC && USE_IN_LIBIO
-      if (_IO_fwide (stderr, 0) > 0)
-       __fwprintf (stderr, L"%s:%d: ", file_name, line_number);
-      else
+#if _LIBC
+      __fxprintf (NULL, "%s:%d: ", file_name, line_number);
+#else
+      fprintf (stderr, "%s:%d: ", file_name, line_number);
 #endif
-       fprintf (stderr, "%s:%d: ", file_name, line_number);
     }
 
 #ifdef VA_START
@@ -343,7 +397,7 @@ error_at_line (status, errnum, file_name, line_number, message, va_alist)
 
   ++error_message_count;
   if (errnum)
-    fprintf (stderr, ": %s", strerror (errnum));
+    print_errno_message (errnum);
   putc ('\n', stderr);
   fflush (stderr);
   if (status)
@@ -351,10 +405,9 @@ error_at_line (status, errnum, file_name, line_number, message, va_alist)
 #endif
 
 #ifdef _LIBC
-# ifdef USE_IN_LIBIO
   _IO_funlockfile (stderr);
-# else
-  __funlockfile (stderr);
+# ifdef __libc_ptf_call
+  __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
 # endif
 #endif
 }