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