1 /* error.c -- error handler for noninteractive utilities
2 Copyright (C) 1990, 91, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
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)
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.
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. */
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.
31 #if defined(HAVE_SYSLOG)
35 #if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC || HAVE_STDARG_H
38 # define VA_START(args, lastarg) va_start(args, lastarg)
41 # define VA_START(args, lastarg) va_start(args)
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;
48 #if STDC_HEADERS || _LIBC
57 #include "fetchmail.h"
58 #define MALLOC(n) xmalloc(n)
59 #define REALLOC(n,s) xrealloc(n,s)
61 /* If NULL, error will flush stderr, 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) (
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;
77 /* This variable is incremented each time `error' is called. */
78 unsigned int error_message_count;
81 /* In the GNU C library, there is a predefined variable for this. */
83 # define program_name program_invocation_name
88 /* The calling program should define program_name and set it to the
89 name of the executing program. */
90 extern char *program_name;
92 # if !HAVE_STRERROR && !defined(strerror)
93 char *strerror (errnum)
96 extern char *sys_errlist[];
99 if (errnum > 0 && errnum <= sys_nerr)
100 return sys_errlist[errnum];
101 return GT_("Unknown system error");
103 # endif /* HAVE_STRERROR */
106 /* Print the program name and error message MESSAGE, which is a printf-style
107 format string with optional args.
108 If ERRNUM is nonzero, print its corresponding system error message. */
113 report (FILE *errfp, const char *message, ...)
115 report (FILE *errfp, message, va_alist)
124 /* If a partially built message exists, print it now so it's not lost. */
125 if (partial_message_size_used != 0)
127 partial_message_size_used = 0;
128 report (errfp, 0, GT_("%s (log message incomplete)"), partial_message);
131 #if defined(HAVE_SYSLOG)
137 VA_START (args, message);
139 priority = (errfp == stderr) ? LOG_ERR : LOG_INFO;
142 vsyslog (priority, message, args);
145 char *a1 = va_arg(args, char *);
146 char *a2 = va_arg(args, char *);
147 char *a3 = va_arg(args, char *);
148 char *a4 = va_arg(args, char *);
149 char *a5 = va_arg(args, char *);
150 char *a6 = va_arg(args, char *);
151 char *a7 = va_arg(args, char *);
152 char *a8 = va_arg(args, char *);
153 syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
164 if (error_print_progname)
165 (*error_print_progname) ();
169 if ( *message == '\n' )
171 fputc( '\n', errfp );
174 fprintf (errfp, "%s: ", program_name);
178 VA_START (args, message);
179 # if HAVE_VPRINTF || _LIBC
180 vfprintf (errfp, message, args);
182 _doprnt (message, args, errfp);
186 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
190 ++error_message_count;
194 * Calling report_init(1) causes error_build and error_complete to write
195 * to errfp without buffering. This is needed for the ticker dots to
198 void report_init(int mode)
202 case 0: /* errfp, buffered */
208 case 1: /* errfp, unbuffered */
214 case -1: /* syslogd */
218 #endif /* HAVE_SYSLOG */
222 /* Build an error message by appending MESSAGE, which is a printf-style
223 format string with optional args, to the existing error message (which may
224 be empty.) The completed error message is finally printed (and reset to
225 empty) by calling error_complete().
226 If an intervening call to report() occurs when a partially constructed
227 message exists, then, in an attempt to keep the messages in their proper
228 sequence, the partial message will be printed as-is (with a trailing
229 newline) before report() prints its message. */
234 report_build (FILE *errfp, const char *message, ...)
236 report_build (FILE *errfp, message, va_alist)
246 /* Make an initial guess for the size of any single message fragment. */
247 if (partial_message_size == 0)
249 partial_message_size_used = 0;
250 partial_message_size = 2048;
251 partial_message = MALLOC (partial_message_size);
254 if (partial_message_size - partial_message_size_used < 1024)
256 partial_message_size += 2048;
257 partial_message = REALLOC (partial_message, partial_message_size);
260 #if defined(VA_START)
261 VA_START (args, message);
262 #if HAVE_VSNPRINTF || _LIBC
265 n = vsnprintf (partial_message + partial_message_size_used,
266 partial_message_size - partial_message_size_used,
269 if (n < partial_message_size - partial_message_size_used)
271 partial_message_size_used += n;
275 partial_message_size += 2048;
276 partial_message = REALLOC (partial_message, partial_message_size);
279 vsprintf (partial_message + partial_message_size_used, message, args);
280 partial_message_size_used += strlen(partial_message+partial_message_size_used);
282 /* Attempt to catch memory overwrites... */
283 if (partial_message_size_used >= partial_message_size)
285 partial_message_size_used = 0;
286 report (stderr, GT_("partial error message buffer overflow"));
294 n = snprintf (partial_message + partial_message_size_used,
295 partial_message_size - partial_message_size_used,
296 message, a1, a2, a3, a4, a5, a6, a7, a8);
298 if (n < partial_message_size - partial_message_size_used)
300 partial_message_size_used += n;
304 partial_message_size += 2048;
305 partial_message = REALLOC (partial_message, partial_message_size);
308 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
310 /* Attempt to catch memory overwrites... */
311 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
313 partial_message_size_used = 0;
314 report (stderr, GT_("partial error message buffer overflow"));
319 if (use_stderr && partial_message_size_used != 0)
321 partial_message_size_used = 0;
322 fputs(partial_message, errfp);
326 /* Complete an error message by appending MESSAGE, which is a printf-style
327 format string with optional args, to the existing error message (which may
328 be empty.) The completed error message is then printed (and reset to
334 report_complete (FILE *errfp, const char *message, ...)
336 report_complete (FILE *errfp, message, va_alist)
346 /* Make an initial guess for the size of any single message fragment. */
347 if (partial_message_size == 0)
349 partial_message_size_used = 0;
350 partial_message_size = 2048;
351 partial_message = MALLOC (partial_message_size);
354 if (partial_message_size - partial_message_size_used < 1024)
356 partial_message_size += 2048;
357 partial_message = REALLOC (partial_message, partial_message_size);
360 #if defined(VA_START)
361 VA_START (args, message);
362 #if HAVE_VSNPRINTF || _LIBC
365 n = vsnprintf (partial_message + partial_message_size_used,
366 partial_message_size - partial_message_size_used,
369 if (n < partial_message_size - partial_message_size_used)
371 partial_message_size_used += n;
375 partial_message_size += 2048;
376 partial_message = REALLOC (partial_message, partial_message_size);
379 vsprintf (partial_message + partial_message_size_used, message, args);
380 partial_message_size_used += strlen(partial_message+partial_message_size_used);
382 /* Attempt to catch memory overwrites... */
383 if (partial_message_size_used >= partial_message_size)
385 partial_message_size_used = 0;
386 report (stderr, GT_("partial error message buffer overflow"));
394 n = snprintf (partial_message + partial_message_size_used,
395 partial_message_size - partial_message_size_used,
396 message, a1, a2, a3, a4, a5, a6, a7, a8);
398 if (n < partial_message_size - partial_message_size_used)
400 partial_message_size_used += n;
404 partial_message_size += 2048;
405 partial_message = REALLOC (partial_message, partial_message_size);
408 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
410 /* Attempt to catch memory overwrites... */
411 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
413 partial_message_size_used = 0;
414 report (stderr, GT_("partial error message buffer overflow"));
419 /* Finally... print it. */
420 partial_message_size_used = 0;
424 fputs(partial_message, errfp);
427 ++error_message_count;
430 report(errfp, "%s", partial_message);
433 /* Sometimes we want to have at most one error per line. This
434 variable controls whether this mode is selected or not. */
435 int error_one_per_line;
439 report_at_line (FILE *errfp, int errnum, const char *file_name,
440 unsigned int line_number, const char *message, ...)
442 report_at_line (FILE *errfp, errnum, file_name, line_number, message, va_alist)
444 const char *file_name;
445 unsigned int line_number;
454 if (error_one_per_line)
456 static const char *old_file_name;
457 static unsigned int old_line_number;
459 if (old_line_number == line_number &&
460 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
461 /* Simply return and print nothing. */
464 old_file_name = file_name;
465 old_line_number = line_number;
468 if (error_print_progname)
469 (*error_print_progname) ();
473 if ( *message == '\n' )
475 fputc( '\n', errfp );
478 fprintf (errfp, "%s:", program_name);
481 if (file_name != NULL)
482 fprintf (errfp, "%s:%d: ", file_name, line_number);
485 VA_START (args, message);
486 # if HAVE_VPRINTF || _LIBC
487 vfprintf (errfp, message, args);
489 _doprnt (message, args, errfp);
493 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
496 ++error_message_count;
498 fprintf (errfp, ": %s", strerror (errnum));