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 char *tmps = strerror(errnum);
230 fprintf (stderr, ": %s", tmps);
233 fprintf (stderr, ": Error %d", errnum);
239 ++error_message_count;
245 * Calling error_init(TRUE) causes error_build and error_complete to write
246 * to stderr without buffering. This is needed for the ticker dots to
249 void error_init(foreground)
252 use_stderr = foreground;
255 /* Build an error message by appending MESSAGE, which is a printf-style
256 format string with optional args, to the existing error message (which may
257 be empty.) The completed error message is finally printed (and reset to
258 empty) by calling error_complete().
259 If an intervening call to error() occurs when a partially constructed
260 message exists, then, in an attempt to keep the messages in their proper
261 sequence, the partial message will be printed as-is (with a trailing newline)
262 before error() prints its message.
266 #if defined(VA_START) && __STDC__
267 error_build (const char *message, ...)
269 error_build (message, va_alist)
279 /* Make an initial guess for the size of any single message fragment. */
280 if (partial_message_size == 0)
282 partial_message_size_used = 0;
283 partial_message_size = 2048;
284 partial_message = xmalloc (partial_message_size);
287 if (partial_message_size - partial_message_size_used < 1024)
289 partial_message_size += 2048;
290 partial_message = xrealloc (partial_message, partial_message_size);
293 #if defined(VA_START)
294 VA_START (args, message);
295 #if HAVE_VSNPRINTF || _LIBC
298 n = vsnprintf (partial_message + partial_message_size_used,
299 partial_message_size - partial_message_size_used,
302 if (n < partial_message_size - partial_message_size_used)
304 partial_message_size_used += n;
308 partial_message_size += 2048;
309 partial_message = xrealloc (partial_message, partial_message_size);
312 vsprintf (partial_message + partial_message_size_used, message, args);
313 partial_message_size_used += strlen(partial_message+partial_message_size_used);
315 /* Attempt to catch memory overwrites... */
316 if (partial_message_size_used >= partial_message_size)
318 partial_message_size_used = 0;
319 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
327 n = snprintf (partial_message + partial_message_size_used,
328 partial_message_size - partial_message_size_used,
329 message, a1, a2, a3, a4, a5, a6, a7, a8);
331 if (n < partial_message_size - partial_message_size_used)
333 partial_message_size_used += n;
337 partial_message_size += 2048;
338 partial_message = xrealloc (partial_message, partial_message_size);
341 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
343 /* Attempt to catch memory overwrites... */
344 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
346 partial_message_size_used = 0;
347 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
352 if (use_stderr && partial_message_size_used != 0)
354 partial_message_size_used = 0;
355 fputs(partial_message, stderr);
359 /* Complete an error message by appending MESSAGE, which is a printf-style
360 format string with optional args, to the existing error message (which may
361 be empty.) The completed error message is then printed (and reset to
366 #if defined(VA_START) && __STDC__
367 error_complete (int status, int errnum, const char *message, ...)
369 error_complete (status, errnum, message, va_alist)
381 /* Make an initial guess for the size of any single message fragment. */
382 if (partial_message_size == 0)
384 partial_message_size_used = 0;
385 partial_message_size = 2048;
386 partial_message = xmalloc (partial_message_size);
389 if (partial_message_size - partial_message_size_used < 1024)
391 partial_message_size += 2048;
392 partial_message = xrealloc (partial_message, partial_message_size);
395 #if defined(VA_START)
396 VA_START (args, message);
397 #if HAVE_VSNPRINTF || _LIBC
400 n = vsnprintf (partial_message + partial_message_size_used,
401 partial_message_size - partial_message_size_used,
404 if (n < partial_message_size - partial_message_size_used)
406 partial_message_size_used += n;
410 partial_message_size += 2048;
411 partial_message = xrealloc (partial_message, partial_message_size);
414 vsprintf (partial_message + partial_message_size_used, message, args);
415 partial_message_size_used += strlen(partial_message+partial_message_size_used);
417 /* Attempt to catch memory overwrites... */
418 if (partial_message_size_used >= partial_message_size)
420 partial_message_size_used = 0;
421 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
429 n = snprintf (partial_message + partial_message_size_used,
430 partial_message_size - partial_message_size_used,
431 message, a1, a2, a3, a4, a5, a6, a7, a8);
433 if (n < partial_message_size - partial_message_size_used)
435 partial_message_size_used += n;
439 partial_message_size += 2048;
440 partial_message = xrealloc (partial_message, partial_message_size);
443 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
445 /* Attempt to catch memory overwrites... */
446 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
448 partial_message_size_used = 0;
449 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
454 /* Finally... print it. */
455 partial_message_size_used = 0;
459 fputs(partial_message, stderr);
462 fprintf (stderr, ": %s", strerror (errnum));
467 ++error_message_count;
473 error (status, errnum, "%s", partial_message);
476 /* Sometimes we want to have at most one error per line. This
477 variable controls whether this mode is selected or not. */
478 int error_one_per_line;
481 #if defined(VA_START) && __STDC__
482 error_at_line (int status, int errnum, const char *file_name,
483 unsigned int line_number, const char *message, ...)
485 error_at_line (status, errnum, file_name, line_number, message, va_alist)
488 const char *file_name;
489 unsigned int line_number;
498 if (error_one_per_line)
500 static const char *old_file_name;
501 static unsigned int old_line_number;
503 if (old_line_number == line_number &&
504 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
505 /* Simply return and print nothing. */
508 old_file_name = file_name;
509 old_line_number = line_number;
512 if (error_print_progname)
513 (*error_print_progname) ();
517 if ( *message == '\n' )
519 fputc( '\n', stderr );
522 fprintf (stderr, "%s:", program_name);
525 if (file_name != NULL)
526 fprintf (stderr, "%s:%d: ", file_name, line_number);
529 VA_START (args, message);
530 # if HAVE_VPRINTF || _LIBC
531 vfprintf (stderr, message, args);
533 _doprnt (message, args, stderr);
537 fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
540 ++error_message_count;
542 fprintf (stderr, ": %s", strerror (errnum));