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);
163 syslog (priority, msg, a1, a2, a3, a4, a5, a6, a7, a8);
169 vsyslog (priority, message, args);
171 syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
182 if (error_print_progname)
183 (*error_print_progname) ();
187 if ( *message == '\n' )
189 fputc( '\n', stderr );
192 fprintf (stderr, "%s: ", program_name);
196 VA_START (args, message);
197 # if HAVE_VPRINTF || _LIBC
198 vfprintf (stderr, message, args);
200 _doprnt (message, args, stderr);
204 fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
208 fprintf (stderr, ": %s", strerror (errnum));
212 ++error_message_count;
218 * Calling error_init(TRUE) causes error_build and error_complete to write
219 * to stderr without buffering. This is needed for the ticker dots to
222 void error_init(foreground)
225 use_stderr = foreground;
228 /* Build an error message by appending MESSAGE, which is a printf-style
229 format string with optional args, to the existing error message (which may
230 be empty.) The completed error message is finally printed (and reset to
231 empty) by calling error_complete().
232 If an intervening call to error() occurs when a partially constructed
233 message exists, then, in an attempt to keep the messages in their proper
234 sequence, the partial message will be printed as-is (with a trailing newline)
235 before error() prints its message.
239 #if defined(VA_START) && __STDC__
240 error_build (const char *message, ...)
242 error_build (message, va_alist)
252 /* Make an initial guess for the size of any single message fragment. */
253 if (partial_message_size == 0)
255 partial_message_size_used = 0;
256 partial_message_size = 2048;
257 partial_message = xmalloc (partial_message_size);
260 if (partial_message_size - partial_message_size_used < 1024)
262 partial_message_size += 2048;
263 partial_message = xrealloc (partial_message, partial_message_size);
266 #if defined(VA_START)
267 VA_START (args, message);
268 #if HAVE_VSNPRINTF || _LIBC
271 n = vsnprintf (partial_message + partial_message_size_used,
272 partial_message_size - partial_message_size_used,
275 if (n < partial_message_size - partial_message_size_used)
277 partial_message_size_used += n;
281 partial_message_size += 2048;
282 partial_message = xrealloc (partial_message, partial_message_size);
285 vsprintf (partial_message + partial_message_size_used, message, args);
286 partial_message_size_used += strlen(partial_message+partial_message_size_used);
288 /* Attempt to catch memory overwrites... */
289 if (partial_message_size_used >= partial_message_size)
291 partial_message_size_used = 0;
292 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
300 n = snprintf (partial_message + partial_message_size_used,
301 partial_message_size - partial_message_size_used,
302 message, a1, a2, a3, a4, a5, a6, a7, a8);
304 if (n < partial_message_size - partial_message_size_used)
306 partial_message_size_used += n;
310 partial_message_size += 2048;
311 partial_message = xrealloc (partial_message, partial_message_size);
314 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
316 /* Attempt to catch memory overwrites... */
317 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
319 partial_message_size_used = 0;
320 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
325 if (use_stderr && partial_message_size_used != 0)
327 partial_message_size_used = 0;
328 fputs(partial_message, stderr);
332 /* Complete an error message by appending MESSAGE, which is a printf-style
333 format string with optional args, to the existing error message (which may
334 be empty.) The completed error message is then printed (and reset to
339 #if defined(VA_START) && __STDC__
340 error_complete (int status, int errnum, const char *message, ...)
342 error_complete (status, errnum, message, va_alist)
354 /* Make an initial guess for the size of any single message fragment. */
355 if (partial_message_size == 0)
357 partial_message_size_used = 0;
358 partial_message_size = 2048;
359 partial_message = xmalloc (partial_message_size);
362 if (partial_message_size - partial_message_size_used < 1024)
364 partial_message_size += 2048;
365 partial_message = xrealloc (partial_message, partial_message_size);
368 #if defined(VA_START)
369 VA_START (args, message);
370 #if HAVE_VSNPRINTF || _LIBC
373 n = vsnprintf (partial_message + partial_message_size_used,
374 partial_message_size - partial_message_size_used,
377 if (n < partial_message_size - partial_message_size_used)
379 partial_message_size_used += n;
383 partial_message_size += 2048;
384 partial_message = xrealloc (partial_message, partial_message_size);
387 vsprintf (partial_message + partial_message_size_used, message, args);
388 partial_message_size_used += strlen(partial_message+partial_message_size_used);
390 /* Attempt to catch memory overwrites... */
391 if (partial_message_size_used >= partial_message_size)
393 partial_message_size_used = 0;
394 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
402 n = snprintf (partial_message + partial_message_size_used,
403 partial_message_size - partial_message_size_used,
404 message, a1, a2, a3, a4, a5, a6, a7, a8);
406 if (n < partial_message_size - partial_message_size_used)
408 partial_message_size_used += n;
412 partial_message_size += 2048;
413 partial_message = xrealloc (partial_message, partial_message_size);
416 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
418 /* Attempt to catch memory overwrites... */
419 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
421 partial_message_size_used = 0;
422 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
427 /* Finally... print it. */
428 partial_message_size_used = 0;
432 fputs(partial_message, stderr);
435 fprintf (stderr, ": %s", strerror (errnum));
440 ++error_message_count;
446 error (status, errnum, "%s", partial_message);
449 /* Sometimes we want to have at most one error per line. This
450 variable controls whether this mode is selected or not. */
451 int error_one_per_line;
454 #if defined(VA_START) && __STDC__
455 error_at_line (int status, int errnum, const char *file_name,
456 unsigned int line_number, const char *message, ...)
458 error_at_line (status, errnum, file_name, line_number, message, va_alist)
461 const char *file_name;
462 unsigned int line_number;
471 if (error_one_per_line)
473 static const char *old_file_name;
474 static unsigned int old_line_number;
476 if (old_line_number == line_number &&
477 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
478 /* Simply return and print nothing. */
481 old_file_name = file_name;
482 old_line_number = line_number;
485 if (error_print_progname)
486 (*error_print_progname) ();
490 if ( *message == '\n' )
492 fputc( '\n', stderr );
495 fprintf (stderr, "%s:", program_name);
498 if (file_name != NULL)
499 fprintf (stderr, "%s:%d: ", file_name, line_number);
502 VA_START (args, message);
503 # if HAVE_VPRINTF || _LIBC
504 vfprintf (stderr, message, args);
506 _doprnt (message, args, stderr);
510 fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
513 ++error_message_count;
515 fprintf (stderr, ": %s", strerror (errnum));