1*9663SMark.Logan@Sun.COM /* Error handler for noninteractive utilities
2*9663SMark.Logan@Sun.COM    Copyright (C) 1990-1998, 2000-2007 Free Software Foundation, Inc.
3*9663SMark.Logan@Sun.COM    This file is part of the GNU C Library.
4*9663SMark.Logan@Sun.COM 
5*9663SMark.Logan@Sun.COM    This program is free software; you can redistribute it and/or modify
6*9663SMark.Logan@Sun.COM    it under the terms of the GNU General Public License as published by
7*9663SMark.Logan@Sun.COM    the Free Software Foundation; either version 2, or (at your option)
8*9663SMark.Logan@Sun.COM    any later version.
9*9663SMark.Logan@Sun.COM 
10*9663SMark.Logan@Sun.COM    This program is distributed in the hope that it will be useful,
11*9663SMark.Logan@Sun.COM    but WITHOUT ANY WARRANTY; without even the implied warranty of
12*9663SMark.Logan@Sun.COM    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*9663SMark.Logan@Sun.COM    GNU General Public License for more details.
14*9663SMark.Logan@Sun.COM 
15*9663SMark.Logan@Sun.COM    You should have received a copy of the GNU General Public License along
16*9663SMark.Logan@Sun.COM    with this program; if not, write to the Free Software Foundation,
17*9663SMark.Logan@Sun.COM    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
18*9663SMark.Logan@Sun.COM 
19*9663SMark.Logan@Sun.COM /* Written by David MacKenzie <djm@gnu.ai.mit.edu>.  */
20*9663SMark.Logan@Sun.COM 
21*9663SMark.Logan@Sun.COM #if !_LIBC
22*9663SMark.Logan@Sun.COM # include <config.h>
23*9663SMark.Logan@Sun.COM #endif
24*9663SMark.Logan@Sun.COM 
25*9663SMark.Logan@Sun.COM #include "error.h"
26*9663SMark.Logan@Sun.COM 
27*9663SMark.Logan@Sun.COM #include <stdarg.h>
28*9663SMark.Logan@Sun.COM #include <stdio.h>
29*9663SMark.Logan@Sun.COM #include <stdlib.h>
30*9663SMark.Logan@Sun.COM #include <string.h>
31*9663SMark.Logan@Sun.COM 
32*9663SMark.Logan@Sun.COM #if !_LIBC && ENABLE_NLS
33*9663SMark.Logan@Sun.COM # include "gettext.h"
34*9663SMark.Logan@Sun.COM # define _(msgid) gettext (msgid)
35*9663SMark.Logan@Sun.COM #endif
36*9663SMark.Logan@Sun.COM 
37*9663SMark.Logan@Sun.COM #ifdef _LIBC
38*9663SMark.Logan@Sun.COM # include <libintl.h>
39*9663SMark.Logan@Sun.COM # include <stdbool.h>
40*9663SMark.Logan@Sun.COM # include <stdint.h>
41*9663SMark.Logan@Sun.COM # include <wchar.h>
42*9663SMark.Logan@Sun.COM # define mbsrtowcs __mbsrtowcs
43*9663SMark.Logan@Sun.COM #endif
44*9663SMark.Logan@Sun.COM 
45*9663SMark.Logan@Sun.COM #if USE_UNLOCKED_IO
46*9663SMark.Logan@Sun.COM # include "unlocked-io.h"
47*9663SMark.Logan@Sun.COM #endif
48*9663SMark.Logan@Sun.COM 
49*9663SMark.Logan@Sun.COM #ifndef _
50*9663SMark.Logan@Sun.COM # define _(String) String
51*9663SMark.Logan@Sun.COM #endif
52*9663SMark.Logan@Sun.COM 
53*9663SMark.Logan@Sun.COM /* If NULL, error will flush stdout, then print on stderr the program
54*9663SMark.Logan@Sun.COM    name, a colon and a space.  Otherwise, error will call this
55*9663SMark.Logan@Sun.COM    function without parameters instead.  */
56*9663SMark.Logan@Sun.COM void (*error_print_progname) (void);
57*9663SMark.Logan@Sun.COM 
58*9663SMark.Logan@Sun.COM /* This variable is incremented each time `error' is called.  */
59*9663SMark.Logan@Sun.COM unsigned int error_message_count;
60*9663SMark.Logan@Sun.COM 
61*9663SMark.Logan@Sun.COM #ifdef _LIBC
62*9663SMark.Logan@Sun.COM /* In the GNU C library, there is a predefined variable for this.  */
63*9663SMark.Logan@Sun.COM 
64*9663SMark.Logan@Sun.COM # define program_name program_invocation_name
65*9663SMark.Logan@Sun.COM # include <errno.h>
66*9663SMark.Logan@Sun.COM # include <limits.h>
67*9663SMark.Logan@Sun.COM # include <libio/libioP.h>
68*9663SMark.Logan@Sun.COM 
69*9663SMark.Logan@Sun.COM /* In GNU libc we want do not want to use the common name `error' directly.
70*9663SMark.Logan@Sun.COM    Instead make it a weak alias.  */
71*9663SMark.Logan@Sun.COM extern void __error (int status, int errnum, const char *message, ...)
72*9663SMark.Logan@Sun.COM      __attribute__ ((__format__ (__printf__, 3, 4)));
73*9663SMark.Logan@Sun.COM extern void __error_at_line (int status, int errnum, const char *file_name,
74*9663SMark.Logan@Sun.COM 			     unsigned int line_number, const char *message,
75*9663SMark.Logan@Sun.COM 			     ...)
76*9663SMark.Logan@Sun.COM      __attribute__ ((__format__ (__printf__, 5, 6)));;
77*9663SMark.Logan@Sun.COM # define error __error
78*9663SMark.Logan@Sun.COM # define error_at_line __error_at_line
79*9663SMark.Logan@Sun.COM 
80*9663SMark.Logan@Sun.COM # include <libio/iolibio.h>
81*9663SMark.Logan@Sun.COM # define fflush(s) INTUSE(_IO_fflush) (s)
82*9663SMark.Logan@Sun.COM # undef putc
83*9663SMark.Logan@Sun.COM # define putc(c, fp) INTUSE(_IO_putc) (c, fp)
84*9663SMark.Logan@Sun.COM 
85*9663SMark.Logan@Sun.COM # include <bits/libc-lock.h>
86*9663SMark.Logan@Sun.COM 
87*9663SMark.Logan@Sun.COM #else /* not _LIBC */
88*9663SMark.Logan@Sun.COM 
89*9663SMark.Logan@Sun.COM # if !HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P
90*9663SMark.Logan@Sun.COM #  ifndef HAVE_DECL_STRERROR_R
91*9663SMark.Logan@Sun.COM "this configure-time declaration test was not run"
92*9663SMark.Logan@Sun.COM #  endif
93*9663SMark.Logan@Sun.COM char *strerror_r ();
94*9663SMark.Logan@Sun.COM # endif
95*9663SMark.Logan@Sun.COM 
96*9663SMark.Logan@Sun.COM /* The calling program should define program_name and set it to the
97*9663SMark.Logan@Sun.COM    name of the executing program.  */
98*9663SMark.Logan@Sun.COM extern char *program_name;
99*9663SMark.Logan@Sun.COM 
100*9663SMark.Logan@Sun.COM # if HAVE_STRERROR_R || defined strerror_r
101*9663SMark.Logan@Sun.COM #  define __strerror_r strerror_r
102*9663SMark.Logan@Sun.COM # endif	/* HAVE_STRERROR_R || defined strerror_r */
103*9663SMark.Logan@Sun.COM #endif	/* not _LIBC */
104*9663SMark.Logan@Sun.COM 
105*9663SMark.Logan@Sun.COM static void
106*9663SMark.Logan@Sun.COM print_errno_message (int errnum)
107*9663SMark.Logan@Sun.COM {
108*9663SMark.Logan@Sun.COM   char const *s;
109*9663SMark.Logan@Sun.COM 
110*9663SMark.Logan@Sun.COM #if defined HAVE_STRERROR_R || _LIBC
111*9663SMark.Logan@Sun.COM   char errbuf[1024];
112*9663SMark.Logan@Sun.COM # if STRERROR_R_CHAR_P || _LIBC
113*9663SMark.Logan@Sun.COM   s = __strerror_r (errnum, errbuf, sizeof errbuf);
114*9663SMark.Logan@Sun.COM # else
115*9663SMark.Logan@Sun.COM   if (__strerror_r (errnum, errbuf, sizeof errbuf) == 0)
116*9663SMark.Logan@Sun.COM     s = errbuf;
117*9663SMark.Logan@Sun.COM   else
118*9663SMark.Logan@Sun.COM     s = 0;
119*9663SMark.Logan@Sun.COM # endif
120*9663SMark.Logan@Sun.COM #else
121*9663SMark.Logan@Sun.COM   s = strerror (errnum);
122*9663SMark.Logan@Sun.COM #endif
123*9663SMark.Logan@Sun.COM 
124*9663SMark.Logan@Sun.COM #if !_LIBC
125*9663SMark.Logan@Sun.COM   if (! s)
126*9663SMark.Logan@Sun.COM     s = _("Unknown system error");
127*9663SMark.Logan@Sun.COM #endif
128*9663SMark.Logan@Sun.COM 
129*9663SMark.Logan@Sun.COM #if _LIBC
130*9663SMark.Logan@Sun.COM   __fxprintf (NULL, ": %s", s);
131*9663SMark.Logan@Sun.COM #else
132*9663SMark.Logan@Sun.COM   fprintf (stderr, ": %s", s);
133*9663SMark.Logan@Sun.COM #endif
134*9663SMark.Logan@Sun.COM }
135*9663SMark.Logan@Sun.COM 
136*9663SMark.Logan@Sun.COM static void
137*9663SMark.Logan@Sun.COM error_tail (int status, int errnum, const char *message, va_list args)
138*9663SMark.Logan@Sun.COM {
139*9663SMark.Logan@Sun.COM #if _LIBC
140*9663SMark.Logan@Sun.COM   if (_IO_fwide (stderr, 0) > 0)
141*9663SMark.Logan@Sun.COM     {
142*9663SMark.Logan@Sun.COM # define ALLOCA_LIMIT 2000
143*9663SMark.Logan@Sun.COM       size_t len = strlen (message) + 1;
144*9663SMark.Logan@Sun.COM       wchar_t *wmessage = NULL;
145*9663SMark.Logan@Sun.COM       mbstate_t st;
146*9663SMark.Logan@Sun.COM       size_t res;
147*9663SMark.Logan@Sun.COM       const char *tmp;
148*9663SMark.Logan@Sun.COM       bool use_malloc = false;
149*9663SMark.Logan@Sun.COM 
150*9663SMark.Logan@Sun.COM       while (1)
151*9663SMark.Logan@Sun.COM 	{
152*9663SMark.Logan@Sun.COM 	  if (__libc_use_alloca (len * sizeof (wchar_t)))
153*9663SMark.Logan@Sun.COM 	    wmessage = (wchar_t *) alloca (len * sizeof (wchar_t));
154*9663SMark.Logan@Sun.COM 	  else
155*9663SMark.Logan@Sun.COM 	    {
156*9663SMark.Logan@Sun.COM 	      if (!use_malloc)
157*9663SMark.Logan@Sun.COM 		wmessage = NULL;
158*9663SMark.Logan@Sun.COM 
159*9663SMark.Logan@Sun.COM 	      wchar_t *p = (wchar_t *) realloc (wmessage,
160*9663SMark.Logan@Sun.COM 						len * sizeof (wchar_t));
161*9663SMark.Logan@Sun.COM 	      if (p == NULL)
162*9663SMark.Logan@Sun.COM 		{
163*9663SMark.Logan@Sun.COM 		  free (wmessage);
164*9663SMark.Logan@Sun.COM 		  fputws_unlocked (L"out of memory\n", stderr);
165*9663SMark.Logan@Sun.COM 		  return;
166*9663SMark.Logan@Sun.COM 		}
167*9663SMark.Logan@Sun.COM 	      wmessage = p;
168*9663SMark.Logan@Sun.COM 	      use_malloc = true;
169*9663SMark.Logan@Sun.COM 	    }
170*9663SMark.Logan@Sun.COM 
171*9663SMark.Logan@Sun.COM 	  memset (&st, '\0', sizeof (st));
172*9663SMark.Logan@Sun.COM 	  tmp = message;
173*9663SMark.Logan@Sun.COM 
174*9663SMark.Logan@Sun.COM 	  res = mbsrtowcs (wmessage, &tmp, len, &st);
175*9663SMark.Logan@Sun.COM 	  if (res != len)
176*9663SMark.Logan@Sun.COM 	    break;
177*9663SMark.Logan@Sun.COM 
178*9663SMark.Logan@Sun.COM 	  if (__builtin_expect (len >= SIZE_MAX / 2, 0))
179*9663SMark.Logan@Sun.COM 	    {
180*9663SMark.Logan@Sun.COM 	      /* This really should not happen if everything is fine.  */
181*9663SMark.Logan@Sun.COM 	      res = (size_t) -1;
182*9663SMark.Logan@Sun.COM 	      break;
183*9663SMark.Logan@Sun.COM 	    }
184*9663SMark.Logan@Sun.COM 
185*9663SMark.Logan@Sun.COM 	  len *= 2;
186*9663SMark.Logan@Sun.COM 	}
187*9663SMark.Logan@Sun.COM 
188*9663SMark.Logan@Sun.COM       if (res == (size_t) -1)
189*9663SMark.Logan@Sun.COM 	{
190*9663SMark.Logan@Sun.COM 	  /* The string cannot be converted.  */
191*9663SMark.Logan@Sun.COM 	  if (use_malloc)
192*9663SMark.Logan@Sun.COM 	    {
193*9663SMark.Logan@Sun.COM 	      free (wmessage);
194*9663SMark.Logan@Sun.COM 	      use_malloc = false;
195*9663SMark.Logan@Sun.COM 	    }
196*9663SMark.Logan@Sun.COM 	  wmessage = (wchar_t *) L"???";
197*9663SMark.Logan@Sun.COM 	}
198*9663SMark.Logan@Sun.COM 
199*9663SMark.Logan@Sun.COM       __vfwprintf (stderr, wmessage, args);
200*9663SMark.Logan@Sun.COM 
201*9663SMark.Logan@Sun.COM       if (use_malloc)
202*9663SMark.Logan@Sun.COM 	free (wmessage);
203*9663SMark.Logan@Sun.COM     }
204*9663SMark.Logan@Sun.COM   else
205*9663SMark.Logan@Sun.COM #endif
206*9663SMark.Logan@Sun.COM     vfprintf (stderr, message, args);
207*9663SMark.Logan@Sun.COM   va_end (args);
208*9663SMark.Logan@Sun.COM 
209*9663SMark.Logan@Sun.COM   ++error_message_count;
210*9663SMark.Logan@Sun.COM   if (errnum)
211*9663SMark.Logan@Sun.COM     print_errno_message (errnum);
212*9663SMark.Logan@Sun.COM #if _LIBC
213*9663SMark.Logan@Sun.COM   __fxprintf (NULL, "\n");
214*9663SMark.Logan@Sun.COM #else
215*9663SMark.Logan@Sun.COM   putc ('\n', stderr);
216*9663SMark.Logan@Sun.COM #endif
217*9663SMark.Logan@Sun.COM   fflush (stderr);
218*9663SMark.Logan@Sun.COM   if (status)
219*9663SMark.Logan@Sun.COM     exit (status);
220*9663SMark.Logan@Sun.COM }
221*9663SMark.Logan@Sun.COM 
222*9663SMark.Logan@Sun.COM 
223*9663SMark.Logan@Sun.COM /* Print the program name and error message MESSAGE, which is a printf-style
224*9663SMark.Logan@Sun.COM    format string with optional args.
225*9663SMark.Logan@Sun.COM    If ERRNUM is nonzero, print its corresponding system error message.
226*9663SMark.Logan@Sun.COM    Exit with status STATUS if it is nonzero.  */
227*9663SMark.Logan@Sun.COM void
228*9663SMark.Logan@Sun.COM error (int status, int errnum, const char *message, ...)
229*9663SMark.Logan@Sun.COM {
230*9663SMark.Logan@Sun.COM   va_list args;
231*9663SMark.Logan@Sun.COM 
232*9663SMark.Logan@Sun.COM #if defined _LIBC && defined __libc_ptf_call
233*9663SMark.Logan@Sun.COM   /* We do not want this call to be cut short by a thread
234*9663SMark.Logan@Sun.COM      cancellation.  Therefore disable cancellation for now.  */
235*9663SMark.Logan@Sun.COM   int state = PTHREAD_CANCEL_ENABLE;
236*9663SMark.Logan@Sun.COM   __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state),
237*9663SMark.Logan@Sun.COM 		   0);
238*9663SMark.Logan@Sun.COM #endif
239*9663SMark.Logan@Sun.COM 
240*9663SMark.Logan@Sun.COM   fflush (stdout);
241*9663SMark.Logan@Sun.COM #ifdef _LIBC
242*9663SMark.Logan@Sun.COM   _IO_flockfile (stderr);
243*9663SMark.Logan@Sun.COM #endif
244*9663SMark.Logan@Sun.COM   if (error_print_progname)
245*9663SMark.Logan@Sun.COM     (*error_print_progname) ();
246*9663SMark.Logan@Sun.COM   else
247*9663SMark.Logan@Sun.COM     {
248*9663SMark.Logan@Sun.COM #if _LIBC
249*9663SMark.Logan@Sun.COM       __fxprintf (NULL, "%s: ", program_name);
250*9663SMark.Logan@Sun.COM #else
251*9663SMark.Logan@Sun.COM       fprintf (stderr, "%s: ", program_name);
252*9663SMark.Logan@Sun.COM #endif
253*9663SMark.Logan@Sun.COM     }
254*9663SMark.Logan@Sun.COM 
255*9663SMark.Logan@Sun.COM   va_start (args, message);
256*9663SMark.Logan@Sun.COM   error_tail (status, errnum, message, args);
257*9663SMark.Logan@Sun.COM 
258*9663SMark.Logan@Sun.COM #ifdef _LIBC
259*9663SMark.Logan@Sun.COM   _IO_funlockfile (stderr);
260*9663SMark.Logan@Sun.COM # ifdef __libc_ptf_call
261*9663SMark.Logan@Sun.COM   __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
262*9663SMark.Logan@Sun.COM # endif
263*9663SMark.Logan@Sun.COM #endif
264*9663SMark.Logan@Sun.COM }
265*9663SMark.Logan@Sun.COM 
266*9663SMark.Logan@Sun.COM /* Sometimes we want to have at most one error per line.  This
267*9663SMark.Logan@Sun.COM    variable controls whether this mode is selected or not.  */
268*9663SMark.Logan@Sun.COM int error_one_per_line;
269*9663SMark.Logan@Sun.COM 
270*9663SMark.Logan@Sun.COM void
271*9663SMark.Logan@Sun.COM error_at_line (int status, int errnum, const char *file_name,
272*9663SMark.Logan@Sun.COM 	       unsigned int line_number, const char *message, ...)
273*9663SMark.Logan@Sun.COM {
274*9663SMark.Logan@Sun.COM   va_list args;
275*9663SMark.Logan@Sun.COM 
276*9663SMark.Logan@Sun.COM   if (error_one_per_line)
277*9663SMark.Logan@Sun.COM     {
278*9663SMark.Logan@Sun.COM       static const char *old_file_name;
279*9663SMark.Logan@Sun.COM       static unsigned int old_line_number;
280*9663SMark.Logan@Sun.COM 
281*9663SMark.Logan@Sun.COM       if (old_line_number == line_number
282*9663SMark.Logan@Sun.COM 	  && (file_name == old_file_name
283*9663SMark.Logan@Sun.COM 	      || strcmp (old_file_name, file_name) == 0))
284*9663SMark.Logan@Sun.COM 	/* Simply return and print nothing.  */
285*9663SMark.Logan@Sun.COM 	return;
286*9663SMark.Logan@Sun.COM 
287*9663SMark.Logan@Sun.COM       old_file_name = file_name;
288*9663SMark.Logan@Sun.COM       old_line_number = line_number;
289*9663SMark.Logan@Sun.COM     }
290*9663SMark.Logan@Sun.COM 
291*9663SMark.Logan@Sun.COM #if defined _LIBC && defined __libc_ptf_call
292*9663SMark.Logan@Sun.COM   /* We do not want this call to be cut short by a thread
293*9663SMark.Logan@Sun.COM      cancellation.  Therefore disable cancellation for now.  */
294*9663SMark.Logan@Sun.COM   int state = PTHREAD_CANCEL_ENABLE;
295*9663SMark.Logan@Sun.COM   __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state),
296*9663SMark.Logan@Sun.COM 		   0);
297*9663SMark.Logan@Sun.COM #endif
298*9663SMark.Logan@Sun.COM 
299*9663SMark.Logan@Sun.COM   fflush (stdout);
300*9663SMark.Logan@Sun.COM #ifdef _LIBC
301*9663SMark.Logan@Sun.COM   _IO_flockfile (stderr);
302*9663SMark.Logan@Sun.COM #endif
303*9663SMark.Logan@Sun.COM   if (error_print_progname)
304*9663SMark.Logan@Sun.COM     (*error_print_progname) ();
305*9663SMark.Logan@Sun.COM   else
306*9663SMark.Logan@Sun.COM     {
307*9663SMark.Logan@Sun.COM #if _LIBC
308*9663SMark.Logan@Sun.COM       __fxprintf (NULL, "%s:", program_name);
309*9663SMark.Logan@Sun.COM #else
310*9663SMark.Logan@Sun.COM       fprintf (stderr, "%s:", program_name);
311*9663SMark.Logan@Sun.COM #endif
312*9663SMark.Logan@Sun.COM     }
313*9663SMark.Logan@Sun.COM 
314*9663SMark.Logan@Sun.COM #if _LIBC
315*9663SMark.Logan@Sun.COM   __fxprintf (NULL, file_name != NULL ? "%s:%d: " : " ",
316*9663SMark.Logan@Sun.COM 	      file_name, line_number);
317*9663SMark.Logan@Sun.COM #else
318*9663SMark.Logan@Sun.COM   fprintf (stderr, file_name != NULL ? "%s:%d: " : " ",
319*9663SMark.Logan@Sun.COM 	   file_name, line_number);
320*9663SMark.Logan@Sun.COM #endif
321*9663SMark.Logan@Sun.COM 
322*9663SMark.Logan@Sun.COM   va_start (args, message);
323*9663SMark.Logan@Sun.COM   error_tail (status, errnum, message, args);
324*9663SMark.Logan@Sun.COM 
325*9663SMark.Logan@Sun.COM #ifdef _LIBC
326*9663SMark.Logan@Sun.COM   _IO_funlockfile (stderr);
327*9663SMark.Logan@Sun.COM # ifdef __libc_ptf_call
328*9663SMark.Logan@Sun.COM   __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
329*9663SMark.Logan@Sun.COM # endif
330*9663SMark.Logan@Sun.COM #endif
331*9663SMark.Logan@Sun.COM }
332*9663SMark.Logan@Sun.COM 
333*9663SMark.Logan@Sun.COM #ifdef _LIBC
334*9663SMark.Logan@Sun.COM /* Make the weak alias.  */
335*9663SMark.Logan@Sun.COM # undef error
336*9663SMark.Logan@Sun.COM # undef error_at_line
337*9663SMark.Logan@Sun.COM weak_alias (__error, error)
338*9663SMark.Logan@Sun.COM weak_alias (__error_at_line, error_at_line)
339*9663SMark.Logan@Sun.COM #endif
340