]> Pileus Git - ~andy/fetchmail/blob - report.c
45fba86839c0ebb7c71563164df8050bd121c8d9
[~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           {
164           char *a1 = va_arg(args, char *);
165           char *a2 = va_arg(args, char *);
166           char *a3 = va_arg(args, char *);
167           char *a4 = va_arg(args, char *);
168           char *a5 = va_arg(args, char *);
169           char *a6 = va_arg(args, char *);
170           char *a7 = va_arg(args, char *);
171           char *a8 = va_arg(args, char *);
172           syslog (priority, msg, a1, a2, a3, a4, a5, a6, a7, a8);
173           }
174 #endif
175         }
176       else
177         {
178 #ifdef HAVE_VSYSLOG
179           vsyslog (priority, message, args);
180 #else
181           {
182           char *a1 = va_arg(args, char *);
183           char *a2 = va_arg(args, char *);
184           char *a3 = va_arg(args, char *);
185           char *a4 = va_arg(args, char *);
186           char *a5 = va_arg(args, char *);
187           char *a6 = va_arg(args, char *);
188           char *a7 = va_arg(args, char *);
189           char *a8 = va_arg(args, char *);
190           syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
191           }
192 #endif
193         }
194
195 #ifdef VA_START
196       va_end(args);
197 #endif
198     }
199   else
200 #endif
201     {
202       if (error_print_progname)
203         (*error_print_progname) ();
204       else
205         {
206           fflush (stdout);
207           if ( *message == '\n' )
208             {
209               fputc( '\n', stderr );
210               ++message;
211             }
212           fprintf (stderr, "%s: ", program_name);
213         }
214
215 #ifdef VA_START
216       VA_START (args, message);
217 # if HAVE_VPRINTF || _LIBC
218       vfprintf (stderr, message, args);
219 # else
220       _doprnt (message, args, stderr);
221 # endif
222       va_end (args);
223 #else
224       fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
225 #endif
226
227       if (errnum) {
228         char *tmps = strerror(errnum);
229         if (tmps) {
230           fprintf (stderr, ": %s", tmps);
231         }
232         else {
233           fprintf (stderr, ": Error %d", errnum);
234         }
235       }
236       putc ('\n', stderr);
237       fflush (stderr);
238     }
239   ++error_message_count;
240   if (status)
241     exit (status);
242 }
243 \f
244 /*
245  * Calling error_init(TRUE) causes error_build and error_complete to write
246  * to stderr without buffering.  This is needed for the ticker dots to
247  * work correctly.
248  */
249 void error_init(foreground)
250 int foreground;
251 {
252     use_stderr = foreground;
253 }
254 \f
255 /* Build an error message by appending MESSAGE, which is a printf-style
256    format string with optional args, to the existing error message (which may
257    be empty.)  The completed error message is finally printed (and reset to
258    empty) by calling error_complete().
259    If an intervening call to error() occurs when a partially constructed
260    message exists, then, in an attempt to keep the messages in their proper
261    sequence, the partial message will be printed as-is (with a trailing 
262    newline) before error() prints its message. */
263 /* VARARGS */
264
265 void
266 #if defined(VA_START) && __STDC__
267 error_build (const char *message, ...)
268 #else
269 error_build (message, va_alist)
270      char *message;
271      va_dcl
272 #endif
273 {
274 #ifdef VA_START
275   va_list args;
276   int n;
277 #endif
278
279   /* Make an initial guess for the size of any single message fragment.  */
280   if (partial_message_size == 0)
281     {
282       partial_message_size_used = 0;
283       partial_message_size = 2048;
284       partial_message = xmalloc (partial_message_size);
285     }
286   else
287     if (partial_message_size - partial_message_size_used < 1024)
288       {
289         partial_message_size += 2048;
290         partial_message = xrealloc (partial_message, partial_message_size);
291       }
292
293 #if defined(VA_START)
294   VA_START (args, message);
295 #if HAVE_VSNPRINTF || _LIBC
296   for ( ; ; )
297     {
298       n = vsnprintf (partial_message + partial_message_size_used,
299                      partial_message_size - partial_message_size_used,
300                      message, args);
301
302       if (n < partial_message_size - partial_message_size_used)
303         {
304           partial_message_size_used += n;
305           break;
306         }
307
308       partial_message_size += 2048;
309       partial_message = xrealloc (partial_message, partial_message_size);
310     }
311 #else
312   vsprintf (partial_message + partial_message_size_used, message, args);
313   partial_message_size_used += strlen(partial_message+partial_message_size_used);
314
315   /* Attempt to catch memory overwrites... */
316   if (partial_message_size_used >= partial_message_size)
317     {
318       partial_message_size_used = 0;
319       error (PS_UNDEFINED, 0, "partial error message buffer overflow");
320     }
321 #endif
322   va_end (args);
323 #else
324 #if HAVE_SNPRINTF
325   for ( ; ; )
326     {
327       n = snprintf (partial_message + partial_message_size_used,
328                     partial_message_size - partial_message_size_used,
329                     message, a1, a2, a3, a4, a5, a6, a7, a8);
330
331       if (n < partial_message_size - partial_message_size_used)
332         {
333           partial_message_size_used += n;
334           break;
335         }
336
337       partial_message_size += 2048;
338       partial_message = xrealloc (partial_message, partial_message_size);
339     }
340 #else
341   sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
342
343   /* Attempt to catch memory overwrites... */
344   if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
345     {
346       partial_message_size_used = 0;
347       error (PS_UNDEFINED, 0, "partial error message buffer overflow");
348     }
349 #endif
350 #endif
351
352   if (use_stderr && partial_message_size_used != 0)
353     {
354       partial_message_size_used = 0;
355       fputs(partial_message, stderr);
356     }
357 }
358 \f
359 /* Complete an error message by appending MESSAGE, which is a printf-style
360    format string with optional args, to the existing error message (which may
361    be empty.)  The completed error message is then printed (and reset to
362    empty.) */
363 /* VARARGS */
364
365 void
366 #if defined(VA_START) && __STDC__
367 error_complete (int status, int errnum, const char *message, ...)
368 #else
369 error_complete (status, errnum, message, va_alist)
370      int status;
371      int errnum;
372      char *message;
373      va_dcl
374 #endif
375 {
376 #ifdef VA_START
377   va_list args;
378   int n;
379 #endif
380
381   /* Make an initial guess for the size of any single message fragment.  */
382   if (partial_message_size == 0)
383     {
384       partial_message_size_used = 0;
385       partial_message_size = 2048;
386       partial_message = xmalloc (partial_message_size);
387     }
388   else
389     if (partial_message_size - partial_message_size_used < 1024)
390       {
391         partial_message_size += 2048;
392         partial_message = xrealloc (partial_message, partial_message_size);
393       }
394
395 #if defined(VA_START)
396   VA_START (args, message);
397 #if HAVE_VSNPRINTF || _LIBC
398   for ( ; ; )
399     {
400       n = vsnprintf (partial_message + partial_message_size_used,
401                      partial_message_size - partial_message_size_used,
402                      message, args);
403
404       if (n < partial_message_size - partial_message_size_used)
405         {
406           partial_message_size_used += n;
407           break;
408         }
409
410       partial_message_size += 2048;
411       partial_message = xrealloc (partial_message, partial_message_size);
412     }
413 #else
414   vsprintf (partial_message + partial_message_size_used, message, args);
415   partial_message_size_used += strlen(partial_message+partial_message_size_used);
416
417   /* Attempt to catch memory overwrites... */
418   if (partial_message_size_used >= partial_message_size)
419     {
420       partial_message_size_used = 0;
421       error (PS_UNDEFINED, 0, "partial error message buffer overflow");
422     }
423 #endif
424   va_end (args);
425 #else
426 #if HAVE_SNPRINTF
427   for ( ; ; )
428     {
429       n = snprintf (partial_message + partial_message_size_used,
430                     partial_message_size - partial_message_size_used,
431                     message, a1, a2, a3, a4, a5, a6, a7, a8);
432
433       if (n < partial_message_size - partial_message_size_used)
434         {
435           partial_message_size_used += n;
436           break;
437         }
438
439       partial_message_size += 2048;
440       partial_message = xrealloc (partial_message, partial_message_size);
441     }
442 #else
443   sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
444
445   /* Attempt to catch memory overwrites... */
446   if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
447     {
448       partial_message_size_used = 0;
449       error (PS_UNDEFINED, 0, "partial error message buffer overflow");
450     }
451 #endif
452 #endif
453
454   /* Finally... print it.  */
455   partial_message_size_used = 0;
456
457   if (use_stderr)
458     {
459       fputs(partial_message, stderr);
460
461       if (errnum)
462         fprintf (stderr, ": %s", strerror (errnum));
463
464       putc ('\n', stderr);
465       fflush (stderr);
466
467       ++error_message_count;
468
469       if (status)
470           exit(status);
471     }
472   else
473     error (status, errnum, "%s", partial_message);
474 }
475 \f
476 /* Sometimes we want to have at most one error per line.  This
477    variable controls whether this mode is selected or not.  */
478 int error_one_per_line;
479
480 void
481 #if defined(VA_START) && __STDC__
482 error_at_line (int status, int errnum, const char *file_name,
483                unsigned int line_number, const char *message, ...)
484 #else
485 error_at_line (status, errnum, file_name, line_number, message, va_alist)
486      int status;
487      int errnum;
488      const char *file_name;
489      unsigned int line_number;
490      char *message;
491      va_dcl
492 #endif
493 {
494 #ifdef VA_START
495   va_list args;
496 #endif
497
498   if (error_one_per_line)
499     {
500       static const char *old_file_name;
501       static unsigned int old_line_number;
502
503       if (old_line_number == line_number &&
504           (file_name == old_file_name || !strcmp (old_file_name, file_name)))
505         /* Simply return and print nothing.  */
506         return;
507
508       old_file_name = file_name;
509       old_line_number = line_number;
510     }
511
512   if (error_print_progname)
513     (*error_print_progname) ();
514   else
515     {
516       fflush (stdout);
517       if ( *message == '\n' )
518         {
519           fputc( '\n', stderr );
520           ++message;
521         }
522       fprintf (stderr, "%s:", program_name);
523     }
524
525   if (file_name != NULL)
526     fprintf (stderr, "%s:%d: ", file_name, line_number);
527
528 #ifdef VA_START
529   VA_START (args, message);
530 # if HAVE_VPRINTF || _LIBC
531   vfprintf (stderr, message, args);
532 # else
533   _doprnt (message, args, stderr);
534 # endif
535   va_end (args);
536 #else
537   fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
538 #endif
539
540   ++error_message_count;
541   if (errnum)
542     fprintf (stderr, ": %s", strerror (errnum));
543   putc ('\n', stderr);
544   fflush (stderr);
545   if (status)
546     exit (status);
547 }