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)
42 #if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC || HAVE_STDARG_H
45 # define VA_START(args, lastarg) va_start(args, lastarg)
48 # define VA_START(args, lastarg) va_start(args)
51 # define va_alist a1, a2, a3, a4, a5, a6, a7, a8
52 # define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
55 #if STDC_HEADERS || _LIBC
63 # define _(String) String
66 #include "fetchmail.h"
67 #define MALLOC(n) xmalloc(n)
68 #define REALLOC(n,s) xrealloc(n,s)
70 /* If NULL, error will flush stdout, then print on stderr the program
71 name, a colon and a space. Otherwise, error will call this
72 function without parameters instead. */
73 void (*error_print_progname) (
79 /* Used by error_build() and error_complete() to accumulate partial messages. */
80 static unsigned int partial_message_size = 0;
81 static unsigned int partial_message_size_used = 0;
82 static char *partial_message;
83 static unsigned use_stderr;
84 static unsigned int use_syslog;
86 /* This variable is incremented each time `error' is called. */
87 unsigned int error_message_count;
91 /* In the GNU C library, there is a predefined variable for this. */
93 # define program_name program_invocation_name
98 /* The calling program should define program_name and set it to the
99 name of the executing program. */
100 extern char *program_name;
103 # ifndef strerror /* On some systems, strerror is a macro */
108 private_strerror (errnum)
111 extern char *sys_errlist[];
114 if (errnum > 0 && errnum <= sys_nerr)
115 return sys_errlist[errnum];
116 return _("Unknown system error");
118 # define strerror private_strerror
119 # endif /* HAVE_STRERROR */
122 /* Print the program name and error message MESSAGE, which is a printf-style
123 format string with optional args.
124 If ERRNUM is nonzero, print its corresponding system error message.
125 Exit with status STATUS if it is nonzero. */
130 error (int status, int errnum, const char *message, ...)
132 error (status, errnum, message, va_alist)
143 /* If a partially built message exists, print it now so it's not lost. */
144 if (partial_message_size_used != 0)
146 partial_message_size_used = 0;
147 error (0, 0, "%s (log message incomplete)", partial_message);
150 #if defined(HAVE_SYSLOG)
156 VA_START (args, message);
158 priority = status? LOG_ALERT : errnum? LOG_ERR : LOG_INFO;
162 char *msg = alloca (strlen (message) + 5);
164 strcpy (msg, message);
165 strcat (msg, ": %m");
169 vsyslog (priority, msg, args);
172 char *a1 = va_arg(args, char *);
173 char *a2 = va_arg(args, char *);
174 char *a3 = va_arg(args, char *);
175 char *a4 = va_arg(args, char *);
176 char *a5 = va_arg(args, char *);
177 char *a6 = va_arg(args, char *);
178 char *a7 = va_arg(args, char *);
179 char *a8 = va_arg(args, char *);
180 syslog (priority, msg, a1, a2, a3, a4, a5, a6, a7, a8);
187 vsyslog (priority, message, args);
190 char *a1 = va_arg(args, char *);
191 char *a2 = va_arg(args, char *);
192 char *a3 = va_arg(args, char *);
193 char *a4 = va_arg(args, char *);
194 char *a5 = va_arg(args, char *);
195 char *a6 = va_arg(args, char *);
196 char *a7 = va_arg(args, char *);
197 char *a8 = va_arg(args, char *);
198 syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
210 if (error_print_progname)
211 (*error_print_progname) ();
215 if ( *message == '\n' )
217 fputc( '\n', stderr );
220 fprintf (stderr, "%s: ", program_name);
224 VA_START (args, message);
225 # if HAVE_VPRINTF || _LIBC
226 vfprintf (stderr, message, args);
228 _doprnt (message, args, stderr);
232 fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
235 if (errnum && errnum != -1) {
236 char *tmps = strerror(errnum);
238 fprintf (stderr, ": %s", tmps);
241 fprintf (stderr, ": Error %d", errnum);
247 ++error_message_count;
253 * Calling error_init(1) causes error_build and error_complete to write
254 * to stderr without buffering. This is needed for the ticker dots to
257 void error_init(int mode)
261 case 0: /* stderr, buffered */
267 case 1: /* stderr, unbuffered */
273 case -1: /* syslogd */
277 #endif /* HAVE_SYSLOG */
281 /* Build an error message by appending MESSAGE, which is a printf-style
282 format string with optional args, to the existing error message (which may
283 be empty.) The completed error message is finally printed (and reset to
284 empty) by calling error_complete().
285 If an intervening call to error() occurs when a partially constructed
286 message exists, then, in an attempt to keep the messages in their proper
287 sequence, the partial message will be printed as-is (with a trailing
288 newline) before error() prints its message. */
293 error_build (const char *message, ...)
295 error_build (message, va_alist)
305 /* Make an initial guess for the size of any single message fragment. */
306 if (partial_message_size == 0)
308 partial_message_size_used = 0;
309 partial_message_size = 2048;
310 partial_message = MALLOC (partial_message_size);
313 if (partial_message_size - partial_message_size_used < 1024)
315 partial_message_size += 2048;
316 partial_message = REALLOC (partial_message, partial_message_size);
319 #if defined(VA_START)
320 VA_START (args, message);
321 #if HAVE_VSNPRINTF || _LIBC
324 n = vsnprintf (partial_message + partial_message_size_used,
325 partial_message_size - partial_message_size_used,
328 if (n < partial_message_size - partial_message_size_used)
330 partial_message_size_used += n;
334 partial_message_size += 2048;
335 partial_message = REALLOC (partial_message, partial_message_size);
338 vsprintf (partial_message + partial_message_size_used, message, args);
339 partial_message_size_used += strlen(partial_message+partial_message_size_used);
341 /* Attempt to catch memory overwrites... */
342 if (partial_message_size_used >= partial_message_size)
344 partial_message_size_used = 0;
345 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
353 n = snprintf (partial_message + partial_message_size_used,
354 partial_message_size - partial_message_size_used,
355 message, a1, a2, a3, a4, a5, a6, a7, a8);
357 if (n < partial_message_size - partial_message_size_used)
359 partial_message_size_used += n;
363 partial_message_size += 2048;
364 partial_message = REALLOC (partial_message, partial_message_size);
367 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
369 /* Attempt to catch memory overwrites... */
370 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
372 partial_message_size_used = 0;
373 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
378 if (use_stderr && partial_message_size_used != 0)
380 partial_message_size_used = 0;
381 fputs(partial_message, stderr);
385 /* Complete an error message by appending MESSAGE, which is a printf-style
386 format string with optional args, to the existing error message (which may
387 be empty.) The completed error message is then printed (and reset to
393 error_complete (int status, int errnum, const char *message, ...)
395 error_complete (status, errnum, message, va_alist)
407 /* Make an initial guess for the size of any single message fragment. */
408 if (partial_message_size == 0)
410 partial_message_size_used = 0;
411 partial_message_size = 2048;
412 partial_message = MALLOC (partial_message_size);
415 if (partial_message_size - partial_message_size_used < 1024)
417 partial_message_size += 2048;
418 partial_message = REALLOC (partial_message, partial_message_size);
421 #if defined(VA_START)
422 VA_START (args, message);
423 #if HAVE_VSNPRINTF || _LIBC
426 n = vsnprintf (partial_message + partial_message_size_used,
427 partial_message_size - partial_message_size_used,
430 if (n < partial_message_size - partial_message_size_used)
432 partial_message_size_used += n;
436 partial_message_size += 2048;
437 partial_message = REALLOC (partial_message, partial_message_size);
440 vsprintf (partial_message + partial_message_size_used, message, args);
441 partial_message_size_used += strlen(partial_message+partial_message_size_used);
443 /* Attempt to catch memory overwrites... */
444 if (partial_message_size_used >= partial_message_size)
446 partial_message_size_used = 0;
447 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
455 n = snprintf (partial_message + partial_message_size_used,
456 partial_message_size - partial_message_size_used,
457 message, a1, a2, a3, a4, a5, a6, a7, a8);
459 if (n < partial_message_size - partial_message_size_used)
461 partial_message_size_used += n;
465 partial_message_size += 2048;
466 partial_message = REALLOC (partial_message, partial_message_size);
469 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
471 /* Attempt to catch memory overwrites... */
472 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
474 partial_message_size_used = 0;
475 error (PS_UNDEFINED, 0, "partial error message buffer overflow");
480 /* Finally... print it. */
481 partial_message_size_used = 0;
485 fputs(partial_message, stderr);
488 fprintf (stderr, ": %s", strerror (errnum));
493 ++error_message_count;
499 error (status, errnum, "%s", partial_message);
502 /* Sometimes we want to have at most one error per line. This
503 variable controls whether this mode is selected or not. */
504 int error_one_per_line;
508 error_at_line (int status, int errnum, const char *file_name,
509 unsigned int line_number, const char *message, ...)
511 error_at_line (status, errnum, file_name, line_number, message, va_alist)
514 const char *file_name;
515 unsigned int line_number;
524 if (error_one_per_line)
526 static const char *old_file_name;
527 static unsigned int old_line_number;
529 if (old_line_number == line_number &&
530 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
531 /* Simply return and print nothing. */
534 old_file_name = file_name;
535 old_line_number = line_number;
538 if (error_print_progname)
539 (*error_print_progname) ();
543 if ( *message == '\n' )
545 fputc( '\n', stderr );
548 fprintf (stderr, "%s:", program_name);
551 if (file_name != NULL)
552 fprintf (stderr, "%s:%d: ", file_name, line_number);
555 VA_START (args, message);
556 # if HAVE_VPRINTF || _LIBC
557 vfprintf (stderr, message, args);
559 _doprnt (message, args, stderr);
563 fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
566 ++error_message_count;
568 fprintf (stderr, ": %s", strerror (errnum));