]> Pileus Git - ~andy/fetchmail/blob - report.c
e1e0b745949918681429eada7f148799dbb45866
[~andy/fetchmail] / report.c
1 /* error.c -- error handler for noninteractive utilities
2    Copyright (C) 1990, 91, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* Written by David MacKenzie <djm@gnu.ai.mit.edu>.
19  * Heavily modified by Dave Bodenstab and ESR.
20  * Bludgeoned into submission for SunOS 4.1.3 by
21  *     Chris Cheyney <cheyney@netcom.com>.
22  * Now it works even when the return from vprintf is unreliable.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <errno.h>
31 #if defined(HAVE_SYSLOG)
32 #include <syslog.h>
33 #endif
34 #if defined(HAVE_ALLOCA_H)
35 #include <alloca.h>
36 #endif
37
38 #if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC
39 # if __STDC__
40 #  include <stdarg.h>
41 #  define VA_START(args, lastarg) va_start(args, lastarg)
42 # else
43 #  include <varargs.h>
44 #  define VA_START(args, lastarg) va_start(args)
45 # endif
46 #else
47 # define va_alist a1, a2, a3, a4, a5, a6, a7, a8
48 # define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
49 #endif
50
51 #if STDC_HEADERS || _LIBC
52 # include <stdlib.h>
53 # include <string.h>
54 #else
55 void exit ();
56 #endif
57
58 #include "fetchmail.h"
59
60 #ifndef _
61 # define _(String) String
62 #endif
63
64 /* If NULL, error will flush stdout, then print on stderr the program
65    name, a colon and a space.  Otherwise, error will call this
66    function without parameters instead.  */
67 void (*error_print_progname) (
68 #if __STDC__ - 0
69                               void
70 #endif
71                               );
72
73 /* Used by error_build() and error_complete() to accumulate partial messages.  */
74 static unsigned int partial_message_size = 0;
75 static unsigned int partial_message_size_used = 0;
76 static char *partial_message;
77 static unsigned use_stderr;
78
79 /* This variable is incremented each time `error' is called.  */
80 unsigned int error_message_count;
81
82 #ifdef _LIBC
83 /* In the GNU C library, there is a predefined variable for this.  */
84
85 # define program_name program_invocation_name
86 # include <errno.h>
87
88 #else
89
90 /* The calling program should define program_name and set it to the
91    name of the executing program.  */
92 extern char *program_name;
93
94 # if HAVE_STRERROR
95 #  ifndef strerror              /* On some systems, strerror is a macro */
96 char *strerror ();
97 #  endif
98 # else
99 static char *
100 private_strerror (errnum)
101      int errnum;
102 {
103   extern char *sys_errlist[];
104   extern int sys_nerr;
105
106   if (errnum > 0 && errnum <= sys_nerr)
107     return sys_errlist[errnum];
108   return _("Unknown system error");
109 }
110 #  define strerror private_strerror
111 # endif /* HAVE_STRERROR */
112 #endif  /* _LIBC */
113
114 /* Print the program name and error message MESSAGE, which is a printf-style
115    format string with optional args.
116    If ERRNUM is nonzero, print its corresponding system error message.
117    Exit with status STATUS if it is nonzero.  */
118 /* VARARGS */
119
120 void
121 #if defined(VA_START) && __STDC__
122 error (int status, int errnum, const char *message, ...)
123 #else
124 error (status, errnum, message, va_alist)
125      int status;
126      int errnum;
127      char *message;
128      va_dcl
129 #endif
130 {
131 #ifdef VA_START
132   va_list args;
133 #endif
134
135   /* If a partially built message exists, print it now so it's not lost.  */
136   if (partial_message_size_used != 0)
137     {
138       partial_message_size_used = 0;
139       error (0, 0, "%s (log message incomplete)", partial_message);
140     }
141
142 #if defined(HAVE_SYSLOG)
143   if (use_syslog)
144     {
145       int priority;
146
147 #ifdef VA_START
148       VA_START (args, message);
149 #endif
150       priority = status? LOG_ALERT : errnum? LOG_ERR : LOG_INFO;
151
152       if (errnum > 0)
153         {
154           char *msg = alloca (strlen (message) + 5);
155
156           strcpy (msg, message);
157           strcat (msg, ": %m");
158
159           errno = errnum;
160 #ifdef HAVE_VSYSLOG
161           vsyslog (priority, msg, args);
162 #else
163           syslog (priority, msg, a1, a2, a3, a4, a5, a6, a7, a8);
164 #endif
165         }
166       else
167         {
168 #ifdef HAVE_VSYSLOG
169           vsyslog (priority, message, args);
170 #else
171           syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
172 #endif
173         }
174
175 #ifdef VA_START
176       va_end(args);
177 #endif
178     }
179   else
180 #endif
181     {
182       if (error_print_progname)
183         (*error_print_progname) ();
184       else
185         {
186           fflush (stdout);
187           if ( *message == '\n' )
188             {
189               fputc( '\n', stderr );
190               ++message;
191             }
192           fprintf (stderr, "%s: ", program_name);
193         }
194
195 #ifdef VA_START
196       VA_START (args, message);
197 # if HAVE_VPRINTF || _LIBC
198       vfprintf (stderr, message, args);
199 # else
200       _doprnt (message, args, stderr);
201 # endif
202       va_end (args);
203 #else
204       fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
205 #endif
206
207       if (errnum)
208         fprintf (stderr, ": %s", strerror (errnum));
209       putc ('\n', stderr);
210       fflush (stderr);
211     }
212   ++error_message_count;
213   if (status)
214     exit (status);
215 }
216 \f
217 /*
218  * Calling error_init(TRUE) causes error_build and error_complete to write
219  * to stderr without buffering.  This is needed for the ticker dots to
220  * work correctly.
221  */
222 void error_init(foreground)
223 int foreground;
224 {
225     use_stderr = foreground;
226 }
227 \f
228 /* Build an error message by appending MESSAGE, which is a printf-style
229    format string with optional args, to the existing error message (which may
230    be empty.)  The completed error message is finally printed (and reset to
231    empty) by calling error_complete().
232    If an intervening call to error() occurs when a partially constructed
233    message exists, then, in an attempt to keep the messages in their proper
234    sequence, the partial message will be printed as-is (with a trailing newline)
235    before error() prints its message.
236 /* VARARGS */
237
238 void
239 #if defined(VA_START) && __STDC__
240 error_build (const char *message, ...)
241 #else
242 error_build (message, va_alist)
243      char *message;
244      va_dcl
245 #endif
246 {
247 #ifdef VA_START
248   va_list args;
249   int n;
250 #endif
251
252   /* Make an initial guess for the size of any single message fragment.  */
253   if (partial_message_size == 0)
254     {
255       partial_message_size_used = 0;
256       partial_message_size = 2048;
257       partial_message = xmalloc (partial_message_size);
258     }
259   else
260     if (partial_message_size - partial_message_size_used < 1024)
261       {
262         partial_message_size += 2048;
263         partial_message = xrealloc (partial_message, partial_message_size);
264       }
265
266 #if defined(VA_START)
267   VA_START (args, message);
268 #if HAVE_VSNPRINTF || _LIBC
269   for ( ; ; )
270     {
271       n = vsnprintf (partial_message + partial_message_size_used,
272                      partial_message_size - partial_message_size_used,
273                      message, args);
274
275       if (n < partial_message_size - partial_message_size_used)
276         {
277           partial_message_size_used += n;
278           break;
279         }
280
281       partial_message_size += 2048;
282       partial_message = xrealloc (partial_message, partial_message_size);
283     }
284 #else
285   vsprintf (partial_message + partial_message_size_used, message, args);
286   partial_message_size_used += strlen(partial_message+partial_message_size_used);
287
288   /* Attempt to catch memory overwrites... */
289   if (partial_message_size_used >= partial_message_size)
290     {
291       partial_message_size_used = 0;
292       error (PS_UNDEFINED, 0, "partial error message buffer overflow");
293     }
294 #endif
295   va_end (args);
296 #else
297 #if HAVE_SNPRINTF
298   for ( ; ; )
299     {
300       n = snprintf (partial_message + partial_message_size_used,
301                     partial_message_size - partial_message_size_used,
302                     message, a1, a2, a3, a4, a5, a6, a7, a8);
303
304       if (n < partial_message_size - partial_message_size_used)
305         {
306           partial_message_size_used += n;
307           break;
308         }
309
310       partial_message_size += 2048;
311       partial_message = xrealloc (partial_message, partial_message_size);
312     }
313 #else
314   sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
315
316   /* Attempt to catch memory overwrites... */
317   if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
318     {
319       partial_message_size_used = 0;
320       error (PS_UNDEFINED, 0, "partial error message buffer overflow");
321     }
322 #endif
323 #endif
324
325   if (use_stderr && partial_message_size_used != 0)
326     {
327       partial_message_size_used = 0;
328       fputs(partial_message, stderr);
329     }
330 }
331 \f
332 /* Complete an error message by appending MESSAGE, which is a printf-style
333    format string with optional args, to the existing error message (which may
334    be empty.)  The completed error message is then printed (and reset to
335    empty.)
336 /* VARARGS */
337
338 void
339 #if defined(VA_START) && __STDC__
340 error_complete (int status, int errnum, const char *message, ...)
341 #else
342 error_complete (status, errnum, message, va_alist)
343      int status;
344      int errnum;
345      char *message;
346      va_dcl
347 #endif
348 {
349 #ifdef VA_START
350   va_list args;
351   int n;
352 #endif
353
354   /* Make an initial guess for the size of any single message fragment.  */
355   if (partial_message_size == 0)
356     {
357       partial_message_size_used = 0;
358       partial_message_size = 2048;
359       partial_message = xmalloc (partial_message_size);
360     }
361   else
362     if (partial_message_size - partial_message_size_used < 1024)
363       {
364         partial_message_size += 2048;
365         partial_message = xrealloc (partial_message, partial_message_size);
366       }
367
368 #if defined(VA_START)
369   VA_START (args, message);
370 #if HAVE_VSNPRINTF || _LIBC
371   for ( ; ; )
372     {
373       n = vsnprintf (partial_message + partial_message_size_used,
374                      partial_message_size - partial_message_size_used,
375                      message, args);
376
377       if (n < partial_message_size - partial_message_size_used)
378         {
379           partial_message_size_used += n;
380           break;
381         }
382
383       partial_message_size += 2048;
384       partial_message = xrealloc (partial_message, partial_message_size);
385     }
386 #else
387   vsprintf (partial_message + partial_message_size_used, message, args);
388   partial_message_size_used += strlen(partial_message+partial_message_size_used);
389
390   /* Attempt to catch memory overwrites... */
391   if (partial_message_size_used >= partial_message_size)
392     {
393       partial_message_size_used = 0;
394       error (PS_UNDEFINED, 0, "partial error message buffer overflow");
395     }
396 #endif
397   va_end (args);
398 #else
399 #if HAVE_SNPRINTF
400   for ( ; ; )
401     {
402       n = snprintf (partial_message + partial_message_size_used,
403                     partial_message_size - partial_message_size_used,
404                     message, a1, a2, a3, a4, a5, a6, a7, a8);
405
406       if (n < partial_message_size - partial_message_size_used)
407         {
408           partial_message_size_used += n;
409           break;
410         }
411
412       partial_message_size += 2048;
413       partial_message = xrealloc (partial_message, partial_message_size);
414     }
415 #else
416   sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
417
418   /* Attempt to catch memory overwrites... */
419   if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
420     {
421       partial_message_size_used = 0;
422       error (PS_UNDEFINED, 0, "partial error message buffer overflow");
423     }
424 #endif
425 #endif
426
427   /* Finally... print it.  */
428   partial_message_size_used = 0;
429
430   if (use_stderr)
431     {
432       fputs(partial_message, stderr);
433
434       if (errnum)
435         fprintf (stderr, ": %s", strerror (errnum));
436
437       putc ('\n', stderr);
438       fflush (stderr);
439
440       ++error_message_count;
441
442       if (status)
443           exit(status);
444     }
445   else
446     error (status, errnum, "%s", partial_message);
447 }
448 \f
449 /* Sometimes we want to have at most one error per line.  This
450    variable controls whether this mode is selected or not.  */
451 int error_one_per_line;
452
453 void
454 #if defined(VA_START) && __STDC__
455 error_at_line (int status, int errnum, const char *file_name,
456                unsigned int line_number, const char *message, ...)
457 #else
458 error_at_line (status, errnum, file_name, line_number, message, va_alist)
459      int status;
460      int errnum;
461      const char *file_name;
462      unsigned int line_number;
463      char *message;
464      va_dcl
465 #endif
466 {
467 #ifdef VA_START
468   va_list args;
469 #endif
470
471   if (error_one_per_line)
472     {
473       static const char *old_file_name;
474       static unsigned int old_line_number;
475
476       if (old_line_number == line_number &&
477           (file_name == old_file_name || !strcmp (old_file_name, file_name)))
478         /* Simply return and print nothing.  */
479         return;
480
481       old_file_name = file_name;
482       old_line_number = line_number;
483     }
484
485   if (error_print_progname)
486     (*error_print_progname) ();
487   else
488     {
489       fflush (stdout);
490       if ( *message == '\n' )
491         {
492           fputc( '\n', stderr );
493           ++message;
494         }
495       fprintf (stderr, "%s:", program_name);
496     }
497
498   if (file_name != NULL)
499     fprintf (stderr, "%s:%d: ", file_name, line_number);
500
501 #ifdef VA_START
502   VA_START (args, message);
503 # if HAVE_VPRINTF || _LIBC
504   vfprintf (stderr, message, args);
505 # else
506   _doprnt (message, args, stderr);
507 # endif
508   va_end (args);
509 #else
510   fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
511 #endif
512
513   ++error_message_count;
514   if (errnum)
515     fprintf (stderr, ": %s", strerror (errnum));
516   putc ('\n', stderr);
517   fflush (stderr);
518   if (status)
519     exit (status);
520 }