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