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. */
120 #if !defined(HAVE_VSYSLOG)
121 #if defined(VA_START) && __STDC__
122 int vsyslog(int priority, char *message, ...)
124 int vsyslog(priority, message, va_alist)
136 string = (char *)malloc(LINELEN);
140 vsprintf(string, message, args);
143 syslog(priority, string);
149 #if defined(VA_START) && __STDC__
150 error (int status, int errnum, const char *message, ...)
152 error (status, errnum, message, va_alist)
163 /* If a partially built message exists, print it now so it's not lost. */
164 if (partial_message_size_used != 0)
166 partial_message_size_used = 0;
167 error (0, 0, "%s (log message incomplete)", partial_message);
170 #if defined(HAVE_SYSLOG)
176 VA_START (args, message);
178 priority = status? LOG_ALERT : errnum? LOG_ERR : LOG_INFO;
182 char *msg = alloca (strlen (message) + 5);
184 strcpy (msg, message);
185 strcat (msg, ": %m");
189 vsyslog (priority, msg, args);
192 syslog (priority, msg, a1, a2, a3, a4, a5, a6, a7, a8);
198 vsyslog (priority, message, args);
201 syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
208 if (error_print_progname)
209 (*error_print_progname) ();
213 if ( *message == '\n' )
215 fputc( '\n', stderr );
218 fprintf (stderr, "%s: ", program_name);
222 VA_START (args, message);
223 # if HAVE_VPRINTF || _LIBC
224 vfprintf (stderr, message, args);
226 _doprnt (message, args, stderr);
230 fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
234 fprintf (stderr, ": %s", strerror (errnum));
238 ++error_message_count;
244 * Calling error_init(TRUE) causes error_build and error_complete to write
245 * to stderr without buffering. This is needed for the ticker dots to
248 void error_init(foreground)
251 use_stderr = foreground;
254 /* Build an error message by appending MESSAGE, which is a printf-style
255 format string with optional args, to the existing error message (which may
256 be empty.) The completed error message is finally printed (and reset to
257 empty) by calling error_complete().
258 If an intervening call to error() occurs when a partially constructed
259 message exists, then, in an attempt to keep the messages in their proper
260 sequence, the partial message will be printed as-is (with a trailing newline)
261 before error() prints its message.
265 #if defined(VA_START) && __STDC__
266 error_build (const char *message, ...)
268 error_build (message, va_alist)
278 /* Make an initial guess for the size of any single message fragment. */
279 if (partial_message_size == 0)
281 partial_message_size_used = 0;
282 partial_message_size = 2048;
283 partial_message = xmalloc (partial_message_size);
286 if (partial_message_size - partial_message_size_used < 1024)
288 partial_message_size += 2048;
289 partial_message = xrealloc (partial_message, partial_message_size);
292 #if defined(VA_START)
293 VA_START (args, message);
294 #if HAVE_VSNPRINTF || _LIBC
297 n = vsnprintf (partial_message + partial_message_size_used,
298 partial_message_size - partial_message_size_used,
301 if (n < partial_message_size - partial_message_size_used)
303 partial_message_size_used += n;
307 partial_message_size += 2048;
308 partial_message = xrealloc (partial_message, partial_message_size);
311 vsprintf (partial_message + partial_message_size_used, message, args);
312 partial_message_size_used += strlen(partial_message+partial_message_size_used);
314 /* Attempt to catch memory overwrites... */
315 if (partial_message_size_used >= partial_message_size)
317 partial_message_size_used = 0;
318 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
326 n = snprintf (partial_message + partial_message_size_used,
327 partial_message_size - partial_message_size_used,
328 message, a1, a2, a3, a4, a5, a6, a7, a8);
330 if (n < partial_message_size - partial_message_size_used)
332 partial_message_size_used += n;
336 partial_message_size += 2048;
337 partial_message = xrealloc (partial_message, partial_message_size);
340 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
342 /* Attempt to catch memory overwrites... */
343 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
345 partial_message_size_used = 0;
346 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
351 if (use_stderr && partial_message_size_used != 0)
353 partial_message_size_used = 0;
354 fputs(partial_message, stderr);
358 /* Complete an error message by appending MESSAGE, which is a printf-style
359 format string with optional args, to the existing error message (which may
360 be empty.) The completed error message is then printed (and reset to
365 #if defined(VA_START) && __STDC__
366 error_complete (int status, int errnum, const char *message, ...)
368 error_complete (status, errnum, message, va_alist)
380 /* Make an initial guess for the size of any single message fragment. */
381 if (partial_message_size == 0)
383 partial_message_size_used = 0;
384 partial_message_size = 2048;
385 partial_message = xmalloc (partial_message_size);
388 if (partial_message_size - partial_message_size_used < 1024)
390 partial_message_size += 2048;
391 partial_message = xrealloc (partial_message, partial_message_size);
394 #if defined(VA_START)
395 VA_START (args, message);
396 #if HAVE_VSNPRINTF || _LIBC
399 n = vsnprintf (partial_message + partial_message_size_used,
400 partial_message_size - partial_message_size_used,
403 if (n < partial_message_size - partial_message_size_used)
405 partial_message_size_used += n;
409 partial_message_size += 2048;
410 partial_message = xrealloc (partial_message, partial_message_size);
413 vsprintf (partial_message + partial_message_size_used, message, args);
414 partial_message_size_used += strlen(partial_message+partial_message_size_used);
416 /* Attempt to catch memory overwrites... */
417 if (partial_message_size_used >= partial_message_size)
419 partial_message_size_used = 0;
420 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
428 n = snprintf (partial_message + partial_message_size_used,
429 partial_message_size - partial_message_size_used,
430 message, a1, a2, a3, a4, a5, a6, a7, a8);
432 if (n < partial_message_size - partial_message_size_used)
434 partial_message_size_used += n;
438 partial_message_size += 2048;
439 partial_message = xrealloc (partial_message, partial_message_size);
442 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
444 /* Attempt to catch memory overwrites... */
445 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
447 partial_message_size_used = 0;
448 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
453 /* Finally... print it. */
454 partial_message_size_used = 0;
458 fputs(partial_message, stderr);
461 fprintf (stderr, ": %s", strerror (errnum));
466 ++error_message_count;
472 error (status, errnum, "%s", partial_message);
475 /* Sometimes we want to have at most one error per line. This
476 variable controls whether this mode is selected or not. */
477 int error_one_per_line;
480 #if defined(VA_START) && __STDC__
481 error_at_line (int status, int errnum, const char *file_name,
482 unsigned int line_number, const char *message, ...)
484 error_at_line (status, errnum, file_name, line_number, message, va_alist)
487 const char *file_name;
488 unsigned int line_number;
497 if (error_one_per_line)
499 static const char *old_file_name;
500 static unsigned int old_line_number;
502 if (old_line_number == line_number &&
503 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
504 /* Simply return and print nothing. */
507 old_file_name = file_name;
508 old_line_number = line_number;
511 if (error_print_progname)
512 (*error_print_progname) ();
516 if ( *message == '\n' )
518 fputc( '\n', stderr );
521 fprintf (stderr, "%s:", program_name);
524 if (file_name != NULL)
525 fprintf (stderr, "%s:%d: ", file_name, line_number);
528 VA_START (args, message);
529 # if HAVE_VPRINTF || _LIBC
530 vfprintf (stderr, message, args);
532 _doprnt (message, args, stderr);
536 fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
539 ++error_message_count;
541 fprintf (stderr, ": %s", strerror (errnum));