Blame misc/error.c

Packit Service 82fcde
/* Error handler for noninteractive utilities
Packit Service 82fcde
   Copyright (C) 1990-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
/* Written by David MacKenzie <djm@gnu.ai.mit.edu>.  */
Packit Service 82fcde
Packit Service 82fcde
#if !_LIBC
Packit Service 82fcde
# include <config.h>
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#include "error.h"
Packit Service 82fcde
Packit Service 82fcde
#include <stdarg.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
Packit Service 82fcde
#if !_LIBC && ENABLE_NLS
Packit Service 82fcde
# include "gettext.h"
Packit Service 82fcde
# define _(msgid) gettext (msgid)
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
# include <libintl.h>
Packit Service 82fcde
# include <stdbool.h>
Packit Service 82fcde
# include <stdint.h>
Packit Service 82fcde
# include <wchar.h>
Packit Service 82fcde
# define mbsrtowcs __mbsrtowcs
Packit Service 82fcde
# define USE_UNLOCKED_IO 0
Packit Service 82fcde
# define _GL_ATTRIBUTE_FORMAT_PRINTF(a, b)
Packit Service 82fcde
# define _GL_ARG_NONNULL(a)
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#if USE_UNLOCKED_IO
Packit Service 82fcde
# include "unlocked-io.h"
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifndef _
Packit Service 82fcde
# define _(String) String
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* If NULL, error will flush stdout, then print on stderr the program
Packit Service 82fcde
   name, a colon and a space.  Otherwise, error will call this
Packit Service 82fcde
   function without parameters instead.  */
Packit Service 82fcde
void (*error_print_progname) (void);
Packit Service 82fcde
Packit Service 82fcde
/* This variable is incremented each time 'error' is called.  */
Packit Service 82fcde
unsigned int error_message_count;
Packit Service 82fcde
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
/* In the GNU C library, there is a predefined variable for this.  */
Packit Service 82fcde
Packit Service 82fcde
# define program_name program_invocation_name
Packit Service 82fcde
# include <errno.h>
Packit Service 82fcde
# include <limits.h>
Packit Service 82fcde
# include <libio/libioP.h>
Packit Service 82fcde
Packit Service 82fcde
/* In GNU libc we want do not want to use the common name 'error' directly.
Packit Service 82fcde
   Instead make it a weak alias.  */
Packit Service 82fcde
extern void __error (int status, int errnum, const char *message, ...)
Packit Service 82fcde
     __attribute__ ((__format__ (__printf__, 3, 4)));
Packit Service 82fcde
extern void __error_at_line (int status, int errnum, const char *file_name,
Packit Service 82fcde
			     unsigned int line_number, const char *message,
Packit Service 82fcde
			     ...)
Packit Service 82fcde
     __attribute__ ((__format__ (__printf__, 5, 6)));;
Packit Service 82fcde
# define error __error
Packit Service 82fcde
# define error_at_line __error_at_line
Packit Service 82fcde
Packit Service 82fcde
# include <libio/iolibio.h>
Packit Service 82fcde
# define fflush(s) _IO_fflush (s)
Packit Service 82fcde
# undef putc
Packit Service 82fcde
# define putc(c, fp) _IO_putc (c, fp)
Packit Service 82fcde
Packit Service 82fcde
# include <libc-lock.h>
Packit Service 82fcde
Packit Service 82fcde
#else /* not _LIBC */
Packit Service 82fcde
Packit Service 82fcde
# include <fcntl.h>
Packit Service 82fcde
# include <unistd.h>
Packit Service 82fcde
Packit Service 82fcde
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
Packit Service 82fcde
/* Get declarations of the native Windows API functions.  */
Packit Service 82fcde
#  define WIN32_LEAN_AND_MEAN
Packit Service 82fcde
#  include <windows.h>
Packit Service 82fcde
/* Get _get_osfhandle.  */
Packit Service 82fcde
#  include "msvc-nothrow.h"
Packit Service 82fcde
# endif
Packit Service 82fcde
Packit Service 82fcde
/* The gnulib override of fcntl is not needed in this file.  */
Packit Service 82fcde
# undef fcntl
Packit Service 82fcde
Packit Service 82fcde
# if !HAVE_DECL_STRERROR_R
Packit Service 82fcde
#  ifndef HAVE_DECL_STRERROR_R
Packit Service 82fcde
"this configure-time declaration test was not run"
Packit Service 82fcde
#  endif
Packit Service 82fcde
#  if STRERROR_R_CHAR_P
Packit Service 82fcde
char *strerror_r ();
Packit Service 82fcde
#  else
Packit Service 82fcde
int strerror_r ();
Packit Service 82fcde
#  endif
Packit Service 82fcde
# endif
Packit Service 82fcde
Packit Service 82fcde
/* The calling program should define program_name and set it to the
Packit Service 82fcde
   name of the executing program.  */
Packit Service 82fcde
extern char *program_name;
Packit Service 82fcde
Packit Service 82fcde
# if HAVE_STRERROR_R || defined strerror_r
Packit Service 82fcde
#  define __strerror_r strerror_r
Packit Service 82fcde
# endif	/* HAVE_STRERROR_R || defined strerror_r */
Packit Service 82fcde
#endif	/* not _LIBC */
Packit Service 82fcde
Packit Service 82fcde
#if !_LIBC
Packit Service 82fcde
/* Return non-zero if FD is open.  */
Packit Service 82fcde
static int
Packit Service 82fcde
is_open (int fd)
Packit Service 82fcde
{
Packit Service 82fcde
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
Packit Service 82fcde
  /* On native Windows: The initial state of unassigned standard file
Packit Service 82fcde
     descriptors is that they are open but point to an INVALID_HANDLE_VALUE.
Packit Service 82fcde
     There is no fcntl, and the gnulib replacement fcntl does not support
Packit Service 82fcde
     F_GETFL.  */
Packit Service 82fcde
  return (HANDLE) _get_osfhandle (fd) != INVALID_HANDLE_VALUE;
Packit Service 82fcde
# else
Packit Service 82fcde
#  ifndef F_GETFL
Packit Service 82fcde
#   error Please port fcntl to your platform
Packit Service 82fcde
#  endif
Packit Service 82fcde
  return 0 <= fcntl (fd, F_GETFL);
Packit Service 82fcde
# endif
Packit Service 82fcde
}
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
flush_stdout (void)
Packit Service 82fcde
{
Packit Service 82fcde
#if !_LIBC
Packit Service 82fcde
  int stdout_fd;
Packit Service 82fcde
Packit Service 82fcde
# if GNULIB_FREOPEN_SAFER
Packit Service 82fcde
  /* Use of gnulib's freopen-safer module normally ensures that
Packit Service 82fcde
       fileno (stdout) == 1
Packit Service 82fcde
     whenever stdout is open.  */
Packit Service 82fcde
  stdout_fd = STDOUT_FILENO;
Packit Service 82fcde
# else
Packit Service 82fcde
  /* POSIX states that fileno (stdout) after fclose is unspecified.  But in
Packit Service 82fcde
     practice it is not a problem, because stdout is statically allocated and
Packit Service 82fcde
     the fd of a FILE stream is stored as a field in its allocated memory.  */
Packit Service 82fcde
  stdout_fd = fileno (stdout);
Packit Service 82fcde
# endif
Packit Service 82fcde
  /* POSIX states that fflush (stdout) after fclose is unspecified; it
Packit Service 82fcde
     is safe in glibc, but not on all other platforms.  fflush (NULL)
Packit Service 82fcde
     is always defined, but too draconian.  */
Packit Service 82fcde
  if (0 <= stdout_fd && is_open (stdout_fd))
Packit Service 82fcde
#endif
Packit Service 82fcde
    fflush (stdout);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
print_errno_message (int errnum)
Packit Service 82fcde
{
Packit Service 82fcde
  char const *s;
Packit Service 82fcde
Packit Service 82fcde
#if defined HAVE_STRERROR_R || _LIBC
Packit Service 82fcde
  char errbuf[1024];
Packit Service 82fcde
# if _LIBC || STRERROR_R_CHAR_P
Packit Service 82fcde
  s = __strerror_r (errnum, errbuf, sizeof errbuf);
Packit Service 82fcde
# else
Packit Service 82fcde
  if (__strerror_r (errnum, errbuf, sizeof errbuf) == 0)
Packit Service 82fcde
    s = errbuf;
Packit Service 82fcde
  else
Packit Service 82fcde
    s = 0;
Packit Service 82fcde
# endif
Packit Service 82fcde
#else
Packit Service 82fcde
  s = strerror (errnum);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#if !_LIBC
Packit Service 82fcde
  if (! s)
Packit Service 82fcde
    s = _("Unknown system error");
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#if _LIBC
Packit Service 82fcde
  __fxprintf (NULL, ": %s", s);
Packit Service 82fcde
#else
Packit Service 82fcde
  fprintf (stderr, ": %s", s);
Packit Service 82fcde
#endif
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void _GL_ATTRIBUTE_FORMAT_PRINTF (3, 0) _GL_ARG_NONNULL ((3))
Packit Service 82fcde
error_tail (int status, int errnum, const char *message, va_list args)
Packit Service 82fcde
{
Packit Service 82fcde
#if _LIBC
Packit Service 82fcde
  if (_IO_fwide (stderr, 0) > 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      size_t len = strlen (message) + 1;
Packit Service 82fcde
      wchar_t *wmessage = NULL;
Packit Service 82fcde
      mbstate_t st;
Packit Service 82fcde
      size_t res;
Packit Service 82fcde
      const char *tmp;
Packit Service 82fcde
      bool use_malloc = false;
Packit Service 82fcde
Packit Service 82fcde
      while (1)
Packit Service 82fcde
	{
Packit Service 82fcde
	  if (__libc_use_alloca (len * sizeof (wchar_t)))
Packit Service 82fcde
	    wmessage = (wchar_t *) alloca (len * sizeof (wchar_t));
Packit Service 82fcde
	  else
Packit Service 82fcde
	    {
Packit Service 82fcde
	      if (!use_malloc)
Packit Service 82fcde
		wmessage = NULL;
Packit Service 82fcde
Packit Service 82fcde
	      wchar_t *p = (wchar_t *) realloc (wmessage,
Packit Service 82fcde
						len * sizeof (wchar_t));
Packit Service 82fcde
	      if (p == NULL)
Packit Service 82fcde
		{
Packit Service 82fcde
		  free (wmessage);
Packit Service 82fcde
		  fputws_unlocked (L"out of memory\n", stderr);
Packit Service 82fcde
		  return;
Packit Service 82fcde
		}
Packit Service 82fcde
	      wmessage = p;
Packit Service 82fcde
	      use_malloc = true;
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  memset (&st, '\0', sizeof (st));
Packit Service 82fcde
	  tmp = message;
Packit Service 82fcde
Packit Service 82fcde
	  res = mbsrtowcs (wmessage, &tmp, len, &st);
Packit Service 82fcde
	  if (res != len)
Packit Service 82fcde
	    break;
Packit Service 82fcde
Packit Service 82fcde
	  if (__builtin_expect (len >= SIZE_MAX / sizeof (wchar_t) / 2, 0))
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* This really should not happen if everything is fine.  */
Packit Service 82fcde
	      res = (size_t) -1;
Packit Service 82fcde
	      break;
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  len *= 2;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      if (res == (size_t) -1)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* The string cannot be converted.  */
Packit Service 82fcde
	  if (use_malloc)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      free (wmessage);
Packit Service 82fcde
	      use_malloc = false;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  wmessage = (wchar_t *) L"???";
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      __vfwprintf (stderr, wmessage, args);
Packit Service 82fcde
Packit Service 82fcde
      if (use_malloc)
Packit Service 82fcde
	free (wmessage);
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
#endif
Packit Service 82fcde
    vfprintf (stderr, message, args);
Packit Service 82fcde
  va_end (args);
Packit Service 82fcde
Packit Service 82fcde
  ++error_message_count;
Packit Service 82fcde
  if (errnum)
Packit Service 82fcde
    print_errno_message (errnum);
Packit Service 82fcde
#if _LIBC
Packit Service 82fcde
  __fxprintf (NULL, "\n");
Packit Service 82fcde
#else
Packit Service 82fcde
  putc ('\n', stderr);
Packit Service 82fcde
#endif
Packit Service 82fcde
  fflush (stderr);
Packit Service 82fcde
  if (status)
Packit Service 82fcde
    exit (status);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Print the program name and error message MESSAGE, which is a printf-style
Packit Service 82fcde
   format string with optional args.
Packit Service 82fcde
   If ERRNUM is nonzero, print its corresponding system error message.
Packit Service 82fcde
   Exit with status STATUS if it is nonzero.  */
Packit Service 82fcde
void
Packit Service 82fcde
error (int status, int errnum, const char *message, ...)
Packit Service 82fcde
{
Packit Service 82fcde
  va_list args;
Packit Service 82fcde
Packit Service 82fcde
#if defined _LIBC && defined __libc_ptf_call
Packit Service 82fcde
  /* We do not want this call to be cut short by a thread
Packit Service 82fcde
     cancellation.  Therefore disable cancellation for now.  */
Packit Service 82fcde
  int state = PTHREAD_CANCEL_ENABLE;
Packit Service 82fcde
  __libc_ptf_call (__pthread_setcancelstate,
Packit Service 82fcde
		   (PTHREAD_CANCEL_DISABLE, &state), 0);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  flush_stdout ();
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
  _IO_flockfile (stderr);
Packit Service 82fcde
#endif
Packit Service 82fcde
  if (error_print_progname)
Packit Service 82fcde
    (*error_print_progname) ();
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
#if _LIBC
Packit Service 82fcde
      __fxprintf (NULL, "%s: ", program_name);
Packit Service 82fcde
#else
Packit Service 82fcde
      fprintf (stderr, "%s: ", program_name);
Packit Service 82fcde
#endif
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  va_start (args, message);
Packit Service 82fcde
  error_tail (status, errnum, message, args);
Packit Service a25727
  va_end (args);
Packit Service 82fcde
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
  _IO_funlockfile (stderr);
Packit Service 82fcde
# ifdef __libc_ptf_call
Packit Service 82fcde
  __libc_ptf_call (__pthread_setcancelstate, (state, NULL), 0);
Packit Service 82fcde
# endif
Packit Service 82fcde
#endif
Packit Service 82fcde
}
Packit Service 82fcde

Packit Service 82fcde
/* Sometimes we want to have at most one error per line.  This
Packit Service 82fcde
   variable controls whether this mode is selected or not.  */
Packit Service 82fcde
int error_one_per_line;
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
error_at_line (int status, int errnum, const char *file_name,
Packit Service 82fcde
	       unsigned int line_number, const char *message, ...)
Packit Service 82fcde
{
Packit Service 82fcde
  va_list args;
Packit Service 82fcde
Packit Service 82fcde
  if (error_one_per_line)
Packit Service 82fcde
    {
Packit Service 82fcde
      static const char *old_file_name;
Packit Service 82fcde
      static unsigned int old_line_number;
Packit Service 82fcde
Packit Service 82fcde
      if (old_line_number == line_number
Packit Service 82fcde
	  && (file_name == old_file_name
Packit Service 82fcde
	      || (old_file_name != NULL
Packit Service 82fcde
		  && file_name != NULL
Packit Service 82fcde
		  && strcmp (old_file_name, file_name) == 0)))
Packit Service 82fcde
Packit Service 82fcde
	/* Simply return and print nothing.  */
Packit Service 82fcde
	return;
Packit Service 82fcde
Packit Service 82fcde
      old_file_name = file_name;
Packit Service 82fcde
      old_line_number = line_number;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
#if defined _LIBC && defined __libc_ptf_call
Packit Service 82fcde
  /* We do not want this call to be cut short by a thread
Packit Service 82fcde
     cancellation.  Therefore disable cancellation for now.  */
Packit Service 82fcde
  int state = PTHREAD_CANCEL_ENABLE;
Packit Service 82fcde
  __libc_ptf_call (__pthread_setcancelstate,
Packit Service 82fcde
		   (PTHREAD_CANCEL_DISABLE, &state),
Packit Service 82fcde
		   0);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  flush_stdout ();
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
  _IO_flockfile (stderr);
Packit Service 82fcde
#endif
Packit Service 82fcde
  if (error_print_progname)
Packit Service 82fcde
    (*error_print_progname) ();
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
#if _LIBC
Packit Service 82fcde
      __fxprintf (NULL, "%s:", program_name);
Packit Service 82fcde
#else
Packit Service 82fcde
      fprintf (stderr, "%s:", program_name);
Packit Service 82fcde
#endif
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
#if _LIBC
Packit Service 82fcde
  __fxprintf (NULL, file_name != NULL ? "%s:%d: " : " ",
Packit Service 82fcde
	      file_name, line_number);
Packit Service 82fcde
#else
Packit Service 82fcde
  fprintf (stderr, file_name != NULL ? "%s:%d: " : " ",
Packit Service 82fcde
	   file_name, line_number);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  va_start (args, message);
Packit Service 82fcde
  error_tail (status, errnum, message, args);
Packit Service a25727
  va_end (args);
Packit Service 82fcde
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
  _IO_funlockfile (stderr);
Packit Service 82fcde
# ifdef __libc_ptf_call
Packit Service 82fcde
  __libc_ptf_call (__pthread_setcancelstate, (state, NULL), 0);
Packit Service 82fcde
# endif
Packit Service 82fcde
#endif
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
/* Make the weak alias.  */
Packit Service 82fcde
# undef error
Packit Service 82fcde
# undef error_at_line
Packit Service 82fcde
weak_alias (__error, error)
Packit Service 82fcde
weak_alias (__error_at_line, error_at_line)
Packit Service 82fcde
#endif