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.
28 #if defined(HAVE_SYSLOG)
31 #if defined(HAVE_ALLOCA_H)
35 #if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC
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
55 #include "fetchmail.h"
58 # define _(String) String
61 /* If NULL, error will flush stdout, 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;
76 /* This variable is incremented each time `error' is called. */
77 unsigned int error_message_count;
80 /* In the GNU C library, there is a predefined variable for this. */
82 # define program_name program_invocation_name
87 /* The calling program should define program_name and set it to the
88 name of the executing program. */
89 extern char *program_name;
92 # ifndef strerror /* On some systems, strerror is a macro */
97 private_strerror (errnum)
100 extern char *sys_errlist[];
103 if (errnum > 0 && errnum <= sys_nerr)
104 return sys_errlist[errnum];
105 return _("Unknown system error");
107 # define strerror private_strerror
108 # endif /* HAVE_STRERROR */
111 /* Print the program name and error message MESSAGE, which is a printf-style
112 format string with optional args.
113 If ERRNUM is nonzero, print its corresponding system error message.
114 Exit with status STATUS if it is nonzero. */
117 #if !defined(HAVE_VSYSLOG) && !defined(VA_START)
118 int vsyslog(priority, message, va_alist)
127 string = (char *)malloc(LINELEN);
130 vsprintf(string, message, args);
133 syslog(priority, string);
139 #if defined(VA_START) && __STDC__
140 error (int status, int errnum, const char *message, ...)
142 error (status, errnum, message, va_alist)
153 /* If a partially built message exists, print it now so it's not lost. */
154 if (partial_message_size_used != 0)
156 partial_message_size_used = 0;
157 error (0, 0, "%s (log message incomplete)", partial_message);
160 #if defined(HAVE_SYSLOG)
166 VA_START (args, message);
168 priority = status? LOG_ALERT : errnum? LOG_ERR : LOG_INFO;
172 char *msg = alloca (strlen (message) + 5);
174 strcpy (msg, message);
175 strcat (msg, ": %m");
179 vsyslog (priority, msg, args);
182 syslog (priority, msg, a1, a2, a3, a4, a5, a6, a7, a8);
188 vsyslog (priority, message, args);
191 syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
198 if (error_print_progname)
199 (*error_print_progname) ();
203 if ( *message == '\n' )
205 fputc( '\n', stderr );
208 fprintf (stderr, "%s: ", program_name);
212 VA_START (args, message);
213 # if HAVE_VPRINTF || _LIBC
214 vfprintf (stderr, message, args);
216 _doprnt (message, args, stderr);
220 fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
224 fprintf (stderr, ": %s", strerror (errnum));
228 ++error_message_count;
234 * Calling error_init(TRUE) causes error_build and error_complete to write
235 * to stderr without buffering. This is needed for the ticker dots to
238 void error_init(foreground)
241 use_stderr = foreground;
244 /* Build an error message by appending MESSAGE, which is a printf-style
245 format string with optional args, to the existing error message (which may
246 be empty.) The completed error message is finally printed (and reset to
247 empty) by calling error_complete().
248 If an intervening call to error() occurs when a partially constructed
249 message exists, then, in an attempt to keep the messages in their proper
250 sequence, the partial message will be printed as-is (with a trailing newline)
251 before error() prints its message.
255 #if defined(VA_START) && __STDC__
256 error_build (const char *message, ...)
258 error_build (message, va_alist)
268 /* Make an initial guess for the size of any single message fragment. */
269 if (partial_message_size == 0)
271 partial_message_size_used = 0;
272 partial_message_size = 512;
273 partial_message = xmalloc (partial_message_size);
276 if (partial_message_size - partial_message_size_used < 256)
278 partial_message_size += 512;
279 partial_message = xrealloc (partial_message, partial_message_size);
282 #if defined(VA_START)
283 VA_START (args, message);
284 #if HAVE_VSNPRINTF || _LIBC
287 n = vsnprintf (partial_message + partial_message_size_used,
288 partial_message_size - partial_message_size_used,
291 if (n < partial_message_size - partial_message_size_used)
293 partial_message_size_used += n;
297 partial_message_size += 512;
298 partial_message = xrealloc (partial_message, partial_message_size);
301 partial_message_size_used += vsprintf (partial_message + partial_message_size_used, message, args);
303 /* Attempt to catch memory overwrites... */
304 if (partial_message_size_used >= partial_message_size)
306 partial_message_size_used = 0;
307 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
315 n = snprintf (partial_message + partial_message_size_used,
316 partial_message_size - partial_message_size_used,
317 message, a1, a2, a3, a4, a5, a6, a7, a8);
319 if (n < partial_message_size - partial_message_size_used)
321 partial_message_size_used += n;
325 partial_message_size += 512;
326 partial_message = xrealloc (partial_message, partial_message_size);
329 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
331 /* Attempt to catch memory overwrites... */
332 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
334 partial_message_size_used = 0;
335 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
340 if (use_stderr && partial_message_size_used != 0)
342 partial_message_size_used = 0;
343 fputs(partial_message, stderr);
347 /* Complete an error message by appending MESSAGE, which is a printf-style
348 format string with optional args, to the existing error message (which may
349 be empty.) The completed error message is then printed (and reset to
354 #if defined(VA_START) && __STDC__
355 error_complete (int status, int errnum, const char *message, ...)
357 error_complete (status, errnum, message, va_alist)
369 /* Make an initial guess for the size of any single message fragment. */
370 if (partial_message_size == 0)
372 partial_message_size_used = 0;
373 partial_message_size = 512;
374 partial_message = xmalloc (partial_message_size);
377 if (partial_message_size - partial_message_size_used < 256)
379 partial_message_size += 512;
380 partial_message = xrealloc (partial_message, partial_message_size);
383 #if defined(VA_START)
384 VA_START (args, message);
385 #if HAVE_VSNPRINTF || _LIBC
388 n = vsnprintf (partial_message + partial_message_size_used,
389 partial_message_size - partial_message_size_used,
392 if (n < partial_message_size - partial_message_size_used)
394 partial_message_size_used += n;
398 partial_message_size += 512;
399 partial_message = xrealloc (partial_message, partial_message_size);
402 partial_message_size_used += vsprintf (partial_message + partial_message_size_used, message, args);
404 /* Attempt to catch memory overwrites... */
405 if (partial_message_size_used >= partial_message_size)
407 partial_message_size_used = 0;
408 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
416 n = snprintf (partial_message + partial_message_size_used,
417 partial_message_size - partial_message_size_used,
418 message, a1, a2, a3, a4, a5, a6, a7, a8);
420 if (n < partial_message_size - partial_message_size_used)
422 partial_message_size_used += n;
426 partial_message_size += 512;
427 partial_message = xrealloc (partial_message, partial_message_size);
430 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
432 /* Attempt to catch memory overwrites... */
433 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
435 partial_message_size_used = 0;
436 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
441 /* Finally... print it. */
442 partial_message_size_used = 0;
446 fputs(partial_message, stderr);
449 fprintf (stderr, ": %s", strerror (errnum));
454 ++error_message_count;
460 error (status, errnum, "%s", partial_message);
463 /* Sometimes we want to have at most one error per line. This
464 variable controls whether this mode is selected or not. */
465 int error_one_per_line;
468 #if defined(VA_START) && __STDC__
469 error_at_line (int status, int errnum, const char *file_name,
470 unsigned int line_number, const char *message, ...)
472 error_at_line (status, errnum, file_name, line_number, message, va_alist)
475 const char *file_name;
476 unsigned int line_number;
485 if (error_one_per_line)
487 static const char *old_file_name;
488 static unsigned int old_line_number;
490 if (old_line_number == line_number &&
491 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
492 /* Simply return and print nothing. */
495 old_file_name = file_name;
496 old_line_number = line_number;
499 if (error_print_progname)
500 (*error_print_progname) ();
504 if ( *message == '\n' )
506 fputc( '\n', stderr );
509 fprintf (stderr, "%s:", program_name);
512 if (file_name != NULL)
513 fprintf (stderr, "%s:%d: ", file_name, line_number);
516 VA_START (args, message);
517 # if HAVE_VPRINTF || _LIBC
518 vfprintf (stderr, message, args);
520 _doprnt (message, args, stderr);
524 fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
527 ++error_message_count;
529 fprintf (stderr, ": %s", strerror (errnum));