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