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