]> Pileus Git - ~andy/fetchmail/blob - report.c
Symbolic constants.
[~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 #else
37 #ifdef _AIX
38  #pragma alloca
39 #endif
40 #endif
41
42 #if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC || HAVE_STDARG_H
43 # if HAVE_STDARG_H
44 #  include <stdarg.h>
45 #  define VA_START(args, lastarg) va_start(args, lastarg)
46 # else
47 #  include <varargs.h>
48 #  define VA_START(args, lastarg) va_start(args)
49 # endif
50 #else
51 # define va_alist a1, a2, a3, a4, a5, a6, a7, a8
52 # define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
53 #endif
54
55 #if STDC_HEADERS || _LIBC
56 # include <stdlib.h>
57 # include <string.h>
58 #else
59 void exit ();
60 #endif
61
62 #ifndef _
63 # define _(String) String
64 #endif
65
66 #include "fetchmail.h"
67 #define MALLOC(n)       xmalloc(n)      
68 #define REALLOC(n,s)    xrealloc(n,s)   
69
70 /* If NULL, error will flush stdout, then print on stderr the program
71    name, a colon and a space.  Otherwise, error will call this
72    function without parameters instead.  */
73 void (*error_print_progname) (
74 #if __STDC__ - 0
75                               void
76 #endif
77                               );
78
79 /* Used by error_build() and error_complete() to accumulate partial messages.  */
80 static unsigned int partial_message_size = 0;
81 static unsigned int partial_message_size_used = 0;
82 static char *partial_message;
83 static unsigned use_stderr;
84 static unsigned int use_syslog;
85
86 /* This variable is incremented each time `error' is called.  */
87 unsigned int error_message_count;
88
89
90 #ifdef _LIBC
91 /* In the GNU C library, there is a predefined variable for this.  */
92
93 # define program_name program_invocation_name
94 # include <errno.h>
95
96 #else
97
98 /* The calling program should define program_name and set it to the
99    name of the executing program.  */
100 extern char *program_name;
101
102 # if HAVE_STRERROR
103 #  ifndef strerror              /* On some systems, strerror is a macro */
104 char *strerror ();
105 #  endif
106 # else
107 static char *
108 private_strerror (errnum)
109      int errnum;
110 {
111   extern char *sys_errlist[];
112   extern int sys_nerr;
113
114   if (errnum > 0 && errnum <= sys_nerr)
115     return sys_errlist[errnum];
116   return _("Unknown system error");
117 }
118 #  define strerror private_strerror
119 # endif /* HAVE_STRERROR */
120 #endif  /* _LIBC */
121
122 /* Print the program name and error message MESSAGE, which is a printf-style
123    format string with optional args.
124    If ERRNUM is nonzero, print its corresponding system error message.
125    Exit with status STATUS if it is nonzero.  */
126 /* VARARGS */
127
128 void
129 #ifdef HAVE_STDARG_H
130 error (int status, int errnum, const char *message, ...)
131 #else
132 error (status, errnum, message, va_alist)
133      int status;
134      int errnum;
135      const char *message;
136      va_dcl
137 #endif
138 {
139 #ifdef VA_START
140   va_list args;
141 #endif
142
143   /* If a partially built message exists, print it now so it's not lost.  */
144   if (partial_message_size_used != 0)
145     {
146       partial_message_size_used = 0;
147       error (0, 0, "%s (log message incomplete)", partial_message);
148     }
149
150 #if defined(HAVE_SYSLOG)
151   if (use_syslog)
152     {
153       int priority;
154
155 #ifdef VA_START
156       VA_START (args, message);
157 #endif
158       priority = status? LOG_ALERT : errnum? LOG_ERR : LOG_INFO;
159
160       if (errnum > 0)
161         {
162           char *msg = alloca (strlen (message) + 5);
163
164           strcpy (msg, message);
165           strcat (msg, ": %m");
166
167           errno = errnum;
168 #ifdef HAVE_VSYSLOG
169           vsyslog (priority, msg, args);
170 #else
171           {
172           char *a1 = va_arg(args, char *);
173           char *a2 = va_arg(args, char *);
174           char *a3 = va_arg(args, char *);
175           char *a4 = va_arg(args, char *);
176           char *a5 = va_arg(args, char *);
177           char *a6 = va_arg(args, char *);
178           char *a7 = va_arg(args, char *);
179           char *a8 = va_arg(args, char *);
180           syslog (priority, msg, a1, a2, a3, a4, a5, a6, a7, a8);
181           }
182 #endif
183         }
184       else
185         {
186 #ifdef HAVE_VSYSLOG
187           vsyslog (priority, message, args);
188 #else
189           {
190           char *a1 = va_arg(args, char *);
191           char *a2 = va_arg(args, char *);
192           char *a3 = va_arg(args, char *);
193           char *a4 = va_arg(args, char *);
194           char *a5 = va_arg(args, char *);
195           char *a6 = va_arg(args, char *);
196           char *a7 = va_arg(args, char *);
197           char *a8 = va_arg(args, char *);
198           syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
199           }
200 #endif
201         }
202
203 #ifdef VA_START
204       va_end(args);
205 #endif
206     }
207   else
208 #endif
209     {
210       if (error_print_progname)
211         (*error_print_progname) ();
212       else
213         {
214           fflush (stdout);
215           if ( *message == '\n' )
216             {
217               fputc( '\n', stderr );
218               ++message;
219             }
220           fprintf (stderr, "%s: ", program_name);
221         }
222
223 #ifdef VA_START
224       VA_START (args, message);
225 # if HAVE_VPRINTF || _LIBC
226       vfprintf (stderr, message, args);
227 # else
228       _doprnt (message, args, stderr);
229 # endif
230       va_end (args);
231 #else
232       fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
233 #endif
234
235       if (errnum && errnum != -1) {
236         char *tmps = strerror(errnum);
237         if (tmps) {
238           fprintf (stderr, ": %s", tmps);
239         }
240         else {
241           fprintf (stderr, ": Error %d", errnum);
242         }
243       }
244       putc ('\n', stderr);
245       fflush (stderr);
246     }
247   ++error_message_count;
248   if (status)
249     exit (status);
250 }
251 \f
252 /*
253  * Calling error_init(1) causes error_build and error_complete to write
254  * to stderr without buffering.  This is needed for the ticker dots to
255  * work correctly.
256  */
257 void error_init(int mode)
258 {
259     switch(mode)
260     {
261     case 0:                     /* stderr, buffered */
262     default:
263         use_stderr = FALSE;
264         use_syslog = FALSE;
265         break;
266
267     case 1:                     /* stderr, unbuffered */
268         use_stderr = TRUE;
269         use_syslog = FALSE;
270         break;
271
272 #ifdef HAVE_SYSLOG
273     case -1:                    /* syslogd */
274         use_stderr = FALSE;
275         use_syslog = TRUE;
276         break;
277 #endif /* HAVE_SYSLOG */
278     }
279 }
280 \f
281 /* Build an error message by appending MESSAGE, which is a printf-style
282    format string with optional args, to the existing error message (which may
283    be empty.)  The completed error message is finally printed (and reset to
284    empty) by calling error_complete().
285    If an intervening call to error() occurs when a partially constructed
286    message exists, then, in an attempt to keep the messages in their proper
287    sequence, the partial message will be printed as-is (with a trailing 
288    newline) before error() prints its message. */
289 /* VARARGS */
290
291 void
292 #ifdef HAVE_STDARG_H
293 error_build (const char *message, ...)
294 #else
295 error_build (message, va_alist)
296      const char *message;
297      va_dcl
298 #endif
299 {
300 #ifdef VA_START
301   va_list args;
302   int n;
303 #endif
304
305   /* Make an initial guess for the size of any single message fragment.  */
306   if (partial_message_size == 0)
307     {
308       partial_message_size_used = 0;
309       partial_message_size = 2048;
310       partial_message = MALLOC (partial_message_size);
311     }
312   else
313     if (partial_message_size - partial_message_size_used < 1024)
314       {
315         partial_message_size += 2048;
316         partial_message = REALLOC (partial_message, partial_message_size);
317       }
318
319 #if defined(VA_START)
320   VA_START (args, message);
321 #if HAVE_VSNPRINTF || _LIBC
322   for ( ; ; )
323     {
324       n = vsnprintf (partial_message + partial_message_size_used,
325                      partial_message_size - partial_message_size_used,
326                      message, args);
327
328       if (n < partial_message_size - partial_message_size_used)
329         {
330           partial_message_size_used += n;
331           break;
332         }
333
334       partial_message_size += 2048;
335       partial_message = REALLOC (partial_message, partial_message_size);
336     }
337 #else
338   vsprintf (partial_message + partial_message_size_used, message, args);
339   partial_message_size_used += strlen(partial_message+partial_message_size_used);
340
341   /* Attempt to catch memory overwrites... */
342   if (partial_message_size_used >= partial_message_size)
343     {
344       partial_message_size_used = 0;
345       error (PS_UNDEFINED, 0, "partial error message buffer overflow");
346     }
347 #endif
348   va_end (args);
349 #else
350 #if HAVE_SNPRINTF
351   for ( ; ; )
352     {
353       n = snprintf (partial_message + partial_message_size_used,
354                     partial_message_size - partial_message_size_used,
355                     message, a1, a2, a3, a4, a5, a6, a7, a8);
356
357       if (n < partial_message_size - partial_message_size_used)
358         {
359           partial_message_size_used += n;
360           break;
361         }
362
363       partial_message_size += 2048;
364       partial_message = REALLOC (partial_message, partial_message_size);
365     }
366 #else
367   sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
368
369   /* Attempt to catch memory overwrites... */
370   if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
371     {
372       partial_message_size_used = 0;
373       error (PS_UNDEFINED, 0, "partial error message buffer overflow");
374     }
375 #endif
376 #endif
377
378   if (use_stderr && partial_message_size_used != 0)
379     {
380       partial_message_size_used = 0;
381       fputs(partial_message, stderr);
382     }
383 }
384 \f
385 /* Complete an error message by appending MESSAGE, which is a printf-style
386    format string with optional args, to the existing error message (which may
387    be empty.)  The completed error message is then printed (and reset to
388    empty.) */
389 /* VARARGS */
390
391 void
392 #ifdef HAVE_STDARG_H
393 error_complete (int status, int errnum, const char *message, ...)
394 #else
395 error_complete (status, errnum, message, va_alist)
396      int status;
397      int errnum;
398      const char *message;
399      va_dcl
400 #endif
401 {
402 #ifdef VA_START
403   va_list args;
404   int n;
405 #endif
406
407   /* Make an initial guess for the size of any single message fragment.  */
408   if (partial_message_size == 0)
409     {
410       partial_message_size_used = 0;
411       partial_message_size = 2048;
412       partial_message = MALLOC (partial_message_size);
413     }
414   else
415     if (partial_message_size - partial_message_size_used < 1024)
416       {
417         partial_message_size += 2048;
418         partial_message = REALLOC (partial_message, partial_message_size);
419       }
420
421 #if defined(VA_START)
422   VA_START (args, message);
423 #if HAVE_VSNPRINTF || _LIBC
424   for ( ; ; )
425     {
426       n = vsnprintf (partial_message + partial_message_size_used,
427                      partial_message_size - partial_message_size_used,
428                      message, args);
429
430       if (n < partial_message_size - partial_message_size_used)
431         {
432           partial_message_size_used += n;
433           break;
434         }
435
436       partial_message_size += 2048;
437       partial_message = REALLOC (partial_message, partial_message_size);
438     }
439 #else
440   vsprintf (partial_message + partial_message_size_used, message, args);
441   partial_message_size_used += strlen(partial_message+partial_message_size_used);
442
443   /* Attempt to catch memory overwrites... */
444   if (partial_message_size_used >= partial_message_size)
445     {
446       partial_message_size_used = 0;
447       error (PS_UNDEFINED, 0, "partial error message buffer overflow");
448     }
449 #endif
450   va_end (args);
451 #else
452 #if HAVE_SNPRINTF
453   for ( ; ; )
454     {
455       n = snprintf (partial_message + partial_message_size_used,
456                     partial_message_size - partial_message_size_used,
457                     message, a1, a2, a3, a4, a5, a6, a7, a8);
458
459       if (n < partial_message_size - partial_message_size_used)
460         {
461           partial_message_size_used += n;
462           break;
463         }
464
465       partial_message_size += 2048;
466       partial_message = REALLOC (partial_message, partial_message_size);
467     }
468 #else
469   sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
470
471   /* Attempt to catch memory overwrites... */
472   if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
473     {
474       partial_message_size_used = 0;
475       error (PS_UNDEFINED, 0, "partial error message buffer overflow");
476     }
477 #endif
478 #endif
479
480   /* Finally... print it.  */
481   partial_message_size_used = 0;
482
483   if (use_stderr)
484     {
485       fputs(partial_message, stderr);
486
487       if (errnum)
488         fprintf (stderr, ": %s", strerror (errnum));
489
490       putc ('\n', stderr);
491       fflush (stderr);
492
493       ++error_message_count;
494
495       if (status)
496           exit(status);
497     }
498   else
499     error (status, errnum, "%s", partial_message);
500 }
501 \f
502 /* Sometimes we want to have at most one error per line.  This
503    variable controls whether this mode is selected or not.  */
504 int error_one_per_line;
505
506 void
507 #ifdef HAVE_STDARG_H
508 error_at_line (int status, int errnum, const char *file_name,
509                unsigned int line_number, const char *message, ...)
510 #else
511 error_at_line (status, errnum, file_name, line_number, message, va_alist)
512      int status;
513      int errnum;
514      const char *file_name;
515      unsigned int line_number;
516      const char *message;
517      va_dcl
518 #endif
519 {
520 #ifdef VA_START
521   va_list args;
522 #endif
523
524   if (error_one_per_line)
525     {
526       static const char *old_file_name;
527       static unsigned int old_line_number;
528
529       if (old_line_number == line_number &&
530           (file_name == old_file_name || !strcmp (old_file_name, file_name)))
531         /* Simply return and print nothing.  */
532         return;
533
534       old_file_name = file_name;
535       old_line_number = line_number;
536     }
537
538   if (error_print_progname)
539     (*error_print_progname) ();
540   else
541     {
542       fflush (stdout);
543       if ( *message == '\n' )
544         {
545           fputc( '\n', stderr );
546           ++message;
547         }
548       fprintf (stderr, "%s:", program_name);
549     }
550
551   if (file_name != NULL)
552     fprintf (stderr, "%s:%d: ", file_name, line_number);
553
554 #ifdef VA_START
555   VA_START (args, message);
556 # if HAVE_VPRINTF || _LIBC
557   vfprintf (stderr, message, args);
558 # else
559   _doprnt (message, args, stderr);
560 # endif
561   va_end (args);
562 #else
563   fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
564 #endif
565
566   ++error_message_count;
567   if (errnum)
568     fprintf (stderr, ": %s", strerror (errnum));
569   putc ('\n', stderr);
570   fflush (stderr);
571   if (status)
572     exit (status);
573 }