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)
34 #if defined(HAVE_ALLOCA_H)
38 #if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC
41 # define VA_START(args, lastarg) va_start(args, lastarg)
44 # define VA_START(args, lastarg) va_start(args)
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;
51 #if STDC_HEADERS || _LIBC
58 #include "fetchmail.h"
61 # define _(String) String
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) (
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;
79 /* This variable is incremented each time `error' is called. */
80 unsigned int error_message_count;
83 /* In the GNU C library, there is a predefined variable for this. */
85 # define program_name program_invocation_name
90 /* The calling program should define program_name and set it to the
91 name of the executing program. */
92 extern char *program_name;
95 # ifndef strerror /* On some systems, strerror is a macro */
100 private_strerror (errnum)
103 extern char *sys_errlist[];
106 if (errnum > 0 && errnum <= sys_nerr)
107 return sys_errlist[errnum];
108 return _("Unknown system error");
110 # define strerror private_strerror
111 # endif /* HAVE_STRERROR */
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. */
121 #if defined(VA_START) && __STDC__
122 error (int status, int errnum, const char *message, ...)
124 error (status, errnum, message, va_alist)
135 /* If a partially built message exists, print it now so it's not lost. */
136 if (partial_message_size_used != 0)
138 partial_message_size_used = 0;
139 error (0, 0, "%s (log message incomplete)", partial_message);
142 #if defined(HAVE_SYSLOG)
148 VA_START (args, message);
150 priority = status? LOG_ALERT : errnum? LOG_ERR : LOG_INFO;
154 char *msg = alloca (strlen (message) + 5);
156 strcpy (msg, message);
157 strcat (msg, ": %m");
161 vsyslog (priority, msg, args);
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);
179 vsyslog (priority, message, args);
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);
202 if (error_print_progname)
203 (*error_print_progname) ();
207 if ( *message == '\n' )
209 fputc( '\n', stderr );
212 fprintf (stderr, "%s: ", program_name);
216 VA_START (args, message);
217 # if HAVE_VPRINTF || _LIBC
218 vfprintf (stderr, message, args);
220 _doprnt (message, args, stderr);
224 fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
228 fprintf (stderr, ": %s", strerror (errnum));
232 ++error_message_count;
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
242 void error_init(foreground)
245 use_stderr = foreground;
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.
259 #if defined(VA_START) && __STDC__
260 error_build (const char *message, ...)
262 error_build (message, va_alist)
272 /* Make an initial guess for the size of any single message fragment. */
273 if (partial_message_size == 0)
275 partial_message_size_used = 0;
276 partial_message_size = 2048;
277 partial_message = xmalloc (partial_message_size);
280 if (partial_message_size - partial_message_size_used < 1024)
282 partial_message_size += 2048;
283 partial_message = xrealloc (partial_message, partial_message_size);
286 #if defined(VA_START)
287 VA_START (args, message);
288 #if HAVE_VSNPRINTF || _LIBC
291 n = vsnprintf (partial_message + partial_message_size_used,
292 partial_message_size - partial_message_size_used,
295 if (n < partial_message_size - partial_message_size_used)
297 partial_message_size_used += n;
301 partial_message_size += 2048;
302 partial_message = xrealloc (partial_message, partial_message_size);
305 vsprintf (partial_message + partial_message_size_used, message, args);
306 partial_message_size_used += strlen(partial_message+partial_message_size_used);
308 /* Attempt to catch memory overwrites... */
309 if (partial_message_size_used >= partial_message_size)
311 partial_message_size_used = 0;
312 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
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);
324 if (n < partial_message_size - partial_message_size_used)
326 partial_message_size_used += n;
330 partial_message_size += 2048;
331 partial_message = xrealloc (partial_message, partial_message_size);
334 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
336 /* Attempt to catch memory overwrites... */
337 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
339 partial_message_size_used = 0;
340 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
345 if (use_stderr && partial_message_size_used != 0)
347 partial_message_size_used = 0;
348 fputs(partial_message, stderr);
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
359 #if defined(VA_START) && __STDC__
360 error_complete (int status, int errnum, const char *message, ...)
362 error_complete (status, errnum, message, va_alist)
374 /* Make an initial guess for the size of any single message fragment. */
375 if (partial_message_size == 0)
377 partial_message_size_used = 0;
378 partial_message_size = 2048;
379 partial_message = xmalloc (partial_message_size);
382 if (partial_message_size - partial_message_size_used < 1024)
384 partial_message_size += 2048;
385 partial_message = xrealloc (partial_message, partial_message_size);
388 #if defined(VA_START)
389 VA_START (args, message);
390 #if HAVE_VSNPRINTF || _LIBC
393 n = vsnprintf (partial_message + partial_message_size_used,
394 partial_message_size - partial_message_size_used,
397 if (n < partial_message_size - partial_message_size_used)
399 partial_message_size_used += n;
403 partial_message_size += 2048;
404 partial_message = xrealloc (partial_message, partial_message_size);
407 vsprintf (partial_message + partial_message_size_used, message, args);
408 partial_message_size_used += strlen(partial_message+partial_message_size_used);
410 /* Attempt to catch memory overwrites... */
411 if (partial_message_size_used >= partial_message_size)
413 partial_message_size_used = 0;
414 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
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);
426 if (n < partial_message_size - partial_message_size_used)
428 partial_message_size_used += n;
432 partial_message_size += 2048;
433 partial_message = xrealloc (partial_message, partial_message_size);
436 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
438 /* Attempt to catch memory overwrites... */
439 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
441 partial_message_size_used = 0;
442 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
447 /* Finally... print it. */
448 partial_message_size_used = 0;
452 fputs(partial_message, stderr);
455 fprintf (stderr, ": %s", strerror (errnum));
460 ++error_message_count;
466 error (status, errnum, "%s", partial_message);
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;
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, ...)
478 error_at_line (status, errnum, file_name, line_number, message, va_alist)
481 const char *file_name;
482 unsigned int line_number;
491 if (error_one_per_line)
493 static const char *old_file_name;
494 static unsigned int old_line_number;
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. */
501 old_file_name = file_name;
502 old_line_number = line_number;
505 if (error_print_progname)
506 (*error_print_progname) ();
510 if ( *message == '\n' )
512 fputc( '\n', stderr );
515 fprintf (stderr, "%s:", program_name);
518 if (file_name != NULL)
519 fprintf (stderr, "%s:%d: ", file_name, line_number);
522 VA_START (args, message);
523 # if HAVE_VPRINTF || _LIBC
524 vfprintf (stderr, message, args);
526 _doprnt (message, args, stderr);
530 fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
533 ++error_message_count;
535 fprintf (stderr, ": %s", strerror (errnum));