aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>1996-12-30 18:27:14 +0000
committerEric S. Raymond <esr@thyrsus.com>1996-12-30 18:27:14 +0000
commit28b12aba4ad1b56c1acfea4e20c1a81b91221d45 (patch)
treea9f7706d3dc84c6157ec5226e9a9d4306fcc36e1
parentff4d046f39e3ed641bc5d9925f61d48010c56bfb (diff)
downloadfetchmail-28b12aba4ad1b56c1acfea4e20c1a81b91221d45.tar.gz
fetchmail-28b12aba4ad1b56c1acfea4e20c1a81b91221d45.tar.bz2
fetchmail-28b12aba4ad1b56c1acfea4e20c1a81b91221d45.zip
Dave Bodenstab's error changes.
svn path=/trunk/; revision=705
-rw-r--r--NEWS16
-rw-r--r--acconfig.h4
-rw-r--r--configure.in18
-rw-r--r--driver.c24
-rw-r--r--fetchmail.c34
-rw-r--r--fetchmail.h6
-rw-r--r--fetchmail.man34
-rw-r--r--options.c55
-rw-r--r--report.c271
-rw-r--r--xmalloc.c11
10 files changed, 404 insertions, 69 deletions
diff --git a/NEWS b/NEWS
index f315dbd7..6dae6bf9 100644
--- a/NEWS
+++ b/NEWS
@@ -1,18 +1,20 @@
To Do:
-* The `reading message N ..(M bytes)' messages ideally should go through
- error(), but since they are built piecemeal, they go to stderr. What
- would be needed is an error() variant that didn't write a message until
- it got a trailing \n -- otherwise, if a syslog option were added, these
- messages would wind up as separate syslog calls (probably not the desired
- result).
-
* Chris LewisMoss reports that he gets a parse error when the last line of
his .fetchmailrc is a comment.
Release Notes:
------------------------------------------------------------------------------
+fetchmail-2.7 ()
+
+features --
+
+* New --syslog option by Dave Bodenstab.
+
+bugs --
+
+------------------------------------------------------------------------------
fetchmail-2.6 (Fri Dec 27 12:42:56 EST 1996)
features --
diff --git a/acconfig.h b/acconfig.h
index d6a1399b..9f8434d0 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -32,8 +32,8 @@
/* Define if you have GNU's getopt family of functions. */
#undef HAVE_GETOPTLONG
-/* Define if you have setlinebuf(3) */
-#undef HAVE_SETLINEBUF
+/* Define to enable use of stdio for socket I/O. */
+#undef USE_STDIO
/* Leave that blank line there!! Autoheader needs it.
diff --git a/configure.in b/configure.in
index d988c620..6dea56c5 100644
--- a/configure.in
+++ b/configure.in
@@ -70,6 +70,22 @@ then
LIBS="$LIBS -lkrb -ldes"
fi
+dnl Configure command line options
+opt_enable_stdio=unset
+
+AC_ARG_ENABLE(stdio, --enable-stdio enable stdio for socket I/O, opt_enable_stdio=$enableval)
+
+if test $opt_enable_stdio = unset; then
+ dnl Set USE_STDIO based on $host
+ case $host in
+ *-*-*freebsd*)
+ AC_DEFINE(USE_STDIO)
+ ;;
+ esac
+elif test $opt_enable_stdio = yes; then
+ AC_DEFINE(USE_STDIO)
+fi
+
dnl All AC_CHECK_FUNCs must precede the following AC_SUBSTs
@@ -77,7 +93,7 @@ AC_SUBST(EXTRASRC)
AC_SUBST(EXTRAOBJ)
AC_CHECK_FUNCS(tcsetattr stty setsid seteuid gethostbyname res_search herror \
- strrchr strerror setlinebuf)
+ strrchr strerror setlinebuf syslog snprintf vsnprintf)
dnl AC_FUNC_SETVBUF_REVERSED
diff --git a/driver.c b/driver.c
index 459bfd81..ce09c8e1 100644
--- a/driver.c
+++ b/driver.c
@@ -336,7 +336,7 @@ struct query *ctl; /* query control record */
while (sizeticker >= SIZETICKER)
{
if (outlevel > O_SILENT)
- fputc('.',stderr);
+ error_build(".");
sizeticker -= SIZETICKER;
}
}
@@ -763,6 +763,9 @@ struct query *ctl; /* query control record */
lines++;
}
+ if (outlevel == O_VERBOSE)
+ fputc('\n', stderr);
+
if (ctl->mda[0])
{
int rc;
@@ -897,7 +900,8 @@ const struct method *proto; /* protocol method table */
if ((sockfp = SockOpen(ctl->servernames->id,
ctl->port ? ctl->port : protocol->port)) == NULL)
{
- error(0, errno, "connecting to host");
+ if (errno != EHOSTUNREACH)
+ error(0, errno, "connecting to host");
ok = PS_SOCKET;
goto closeUp;
}
@@ -1013,9 +1017,9 @@ const struct method *proto; /* protocol method table */
{
if (outlevel > O_SILENT)
{
- fprintf(stderr, "skipping message %d", num);
+ error_build("skipping message %d", num);
if (toolarge)
- fprintf(stderr, " (oversized, %d bytes)", msgsizes[num-1]);
+ error_build(" (oversized, %d bytes)", msgsizes[num-1]);
}
}
else
@@ -1028,13 +1032,13 @@ const struct method *proto; /* protocol method table */
if (outlevel > O_SILENT)
{
- fprintf(stderr, "reading message %d", num);
+ error_build("reading message %d", num);
if (len > 0)
- fprintf(stderr, " (%d bytes)", len);
+ error_build(" (%d bytes)", len);
if (outlevel == O_VERBOSE)
- fputc('\n', stderr);
+ error_complete(0, 0, "");
else
- fputc(' ', stderr);
+ error_build(" ");
}
/* read the message and ship it to the output sink */
@@ -1071,7 +1075,7 @@ const struct method *proto; /* protocol method table */
{
deletions++;
if (outlevel > O_SILENT)
- fprintf(stderr, " flushed\n");
+ error_complete(0, 0, " flushed");
ok = (protocol->delete)(sockfp, ctl, num);
if (ok != 0)
goto cleanUp;
@@ -1079,7 +1083,7 @@ const struct method *proto; /* protocol method table */
delete_str(&ctl->newsaved, num);
}
else if (outlevel > O_SILENT)
- fprintf(stderr, " not flushed\n");
+ error_complete(0, 0, " not flushed");
/* perhaps this as many as we're ready to handle */
if (ctl->fetchlimit && ctl->fetchlimit <= num)
diff --git a/fetchmail.c b/fetchmail.c
index 846c4ae7..37ceb0d8 100644
--- a/fetchmail.c
+++ b/fetchmail.c
@@ -19,6 +19,9 @@
#endif
#include <string.h>
#include <signal.h>
+#if defined(HAVE_SYSLOG)
+#include <syslog.h>
+#endif
#include <pwd.h>
#include <errno.h>
#include <sys/time.h>
@@ -51,6 +54,7 @@ int yydebug; /* enable parse debugging */
int poll_interval; /* poll interval in seconds */
int nodetach; /* if TRUE, don't detach daemon process */
char *logfile; /* log file for daemon mode */
+int use_syslog; /* if --syslog was set */
int quitmode; /* if --quit was set */
int check_only; /* if --probe was set */
int cmd_batchlimit; /* if --batchlimit was set */
@@ -85,7 +89,7 @@ static void unlockit(void)
int main (int argc, char **argv)
{
int st, bkgd = FALSE;
- int parsestatus, implicitmode;
+ int parsestatus, implicitmode, sigwakeup;
char *home, *tmpdir, tmpbuf[BUFSIZ];
struct passwd *pw;
struct query *ctl;
@@ -151,8 +155,15 @@ int main (int argc, char **argv)
implicitmode = load_params(argc, argv, optind);
/* set up to do lock protocol */
- strcpy(tmpbuf, home);
- strcat(tmpbuf, "/.fetchmail");
+ if (poll_interval && getuid() == 0) {
+ sigwakeup = SIGHUP;
+ strcpy(tmpbuf, "/var/run/fetchmail.pid");
+ }
+ else {
+ sigwakeup = SIGUSR1;
+ strcpy(tmpbuf, home);
+ strcat(tmpbuf, "/.fetchmail");
+ }
/* perhaps we just want to check options? */
if (versioninfo) {
@@ -259,7 +270,7 @@ int main (int argc, char **argv)
pid);
return(PS_EXCLUDE);
}
- else if (kill(pid, SIGUSR1) == 0)
+ else if (kill(pid, sigwakeup) == 0)
{
fprintf(stderr,
"fetchmail: background fetchmail at %d awakened.\n",
@@ -270,7 +281,7 @@ int main (int argc, char **argv)
{
/*
* Should never happen -- possible only if a background fetchmail
- * croaks after the first kill probe above but before the SIGUSR1
+ * croaks after the first kill probe above but before the SIGUSR1/SIGHUP
* transmission.
*/
fprintf(stderr,
@@ -301,6 +312,11 @@ int main (int argc, char **argv)
/*
* Maybe time to go to demon mode...
*/
+#if defined(HAVE_SYSLOG)
+ if (use_syslog)
+ openlog(program_name, LOG_PID, LOG_MAIL);
+#endif
+
if (poll_interval && !nodetach)
daemonize(logfile, termhook);
@@ -319,7 +335,7 @@ int main (int argc, char **argv)
* side effect of interrupting any sleep that may be going on,
* forcing fetchmail to re-poll its hosts.
*/
- signal(SIGUSR1, donothing);
+ signal(sigwakeup, donothing);
/* here's the exclusion lock */
if ( (lockfp = fopen(lockfile,"w")) != NULL ) {
@@ -372,9 +388,9 @@ int main (int argc, char **argv)
setitimer(ITIMER_REAL,&ntimeout,NULL);
signal(SIGALRM, donothing);
pause();
- if (lastsig == SIGUSR1) {
- signal(SIGALRM, SIG_IGN);
- (void) error(0, 0, "awakened by SIGUSR1");
+ signal(SIGALRM, SIG_IGN);
+ if (lastsig == sigwakeup) {
+ error(0, 0, "awakened by %s", sys_siglist[lastsig]);
}
}
diff --git a/fetchmail.h b/fetchmail.h
index 994bc690..905bc211 100644
--- a/fetchmail.h
+++ b/fetchmail.h
@@ -138,6 +138,7 @@ extern int yydebug; /* enable parse debugging */
extern int poll_interval; /* poll interval in seconds */
extern int nodetach; /* if TRUE, don't detach daemon process */
extern char *logfile; /* log file for daemon mode */
+extern int use_syslog; /* if --syslog was set */
extern int quitmode; /* if --quit was set */
extern int check_only; /* if --check was set */
extern int cmd_batchlimit; /* if --batchlimit was set */
@@ -164,15 +165,20 @@ extern int smtp_response; /* numeric value of SMTP response code */
/* prototypes for globally callable functions */
#if defined(HAVE_STDARG_H)
void error (int status, int errnum, const char *format, ...);
+void error_build (const char *format, ...);
+void error_complete (int status, int errnum, const char *format, ...);
void gen_send (FILE *sockfp, char *, ... );
int gen_transact (FILE *sockfp, char *, ... );
#else
void error ();
+void error_build ();
+void error_complete ();
void gen_send ();
int gen_transact ();
#endif
void *xmalloc(int);
+void *xrealloc(void *, int);
char *xstrdup(const char *);
int do_protocol(struct query *, const struct method *);
diff --git a/fetchmail.man b/fetchmail.man
index 1385bf78..a6ea4142 100644
--- a/fetchmail.man
+++ b/fetchmail.man
@@ -362,6 +362,33 @@ mode into a specified logfile (follow the option with the logfile name).
The logfile is opened for append, so previous messages aren't deleted.
This is primarily useful for debugging configurations.
.PP
+The
+.B --syslog
+option allows you to redirect status and error messages emitted while in
+daemon mode to the
+.IR syslog (3)
+system daemon if available.
+Messages are logged with an id of \fBfetchmail\fR, the facility \fBLOG_MAIL\fR,
+and priorities \fBLOG_ERR\fR, \fBLOG_ALERT\fR or \fBLOG_INFO\fR.
+This option is intended for logging status and error messages which
+indicate the status of the daemon and the results while fetching mail
+from the server(s).
+Error messages for command line options and parsing the \fI.fetchmailrc\fR
+file are still written to stderr, or the specified log file if the
+.B -L
+or
+.B --logfile
+option was used.
+.PP
+The \fI/etc/syslog.conf\fR file might contain the following to log
+all messages from \fIfetchmail\fR to a single file:
+.PP
+.RS
+!fetchmail
+.br
+*.* /var/log/fetchmail
+.RE
+.PP
The
.B \-N
or --nodetach option suppresses detachment of the daemon process
@@ -816,8 +843,11 @@ default location of file associating hosts with last message IDs seen
(used only with newer RFC1725-compliant POP3 servers supporting the
UIDL command).
.TP 5
-$~/.fetchmail
-lock file to help prevent concurrent runs.
+~/.fetchmail
+lock file to help prevent concurrent runs (non-root mode).
+.TP 5
+/var/run/fetchmail.pid
+lock file to help prevent concurrent runs (root mode).
.SH ENVIRONMENT
For correct initialization,
.I fetchmail
diff --git a/options.c b/options.c
index 4bbc593f..4c02d584 100644
--- a/options.c
+++ b/options.c
@@ -25,27 +25,28 @@
#define LA_NODETACH 7
#define LA_QUIT 8
#define LA_LOGFILE 9
-#define LA_RCFILE 10
-#define LA_IDFILE 11
-#define LA_PROTOCOL 12
-#define LA_PORT 13
-#define LA_AUTHENTICATE 14
-#define LA_TIMEOUT 15
-#define LA_USERNAME 16
-#define LA_ALL 17
-#define LA_KILL 18
-#define LA_KEEP 19
-#define LA_FLUSH 20
-#define LA_NOREWRITE 21
-#define LA_LIMIT 22
-#define LA_REMOTEFILE 23
-#define LA_SMTPHOST 24
-#define LA_BATCHLIMIT 25
-#define LA_FETCHLIMIT 26
-#define LA_MDA 27
-#define LA_INTERFACE 28
-#define LA_MONITOR 29
-#define LA_YYDEBUG 30
+#define LA_SYSLOG 10
+#define LA_RCFILE 11
+#define LA_IDFILE 12
+#define LA_PROTOCOL 13
+#define LA_PORT 14
+#define LA_AUTHENTICATE 15
+#define LA_TIMEOUT 16
+#define LA_USERNAME 17
+#define LA_ALL 18
+#define LA_KILL 19
+#define LA_KEEP 20
+#define LA_FLUSH 21
+#define LA_NOREWRITE 22
+#define LA_LIMIT 23
+#define LA_REMOTEFILE 24
+#define LA_SMTPHOST 25
+#define LA_BATCHLIMIT 26
+#define LA_FETCHLIMIT 27
+#define LA_MDA 28
+#define LA_INTERFACE 29
+#define LA_MONITOR 30
+#define LA_YYDEBUG 31
static char *shortoptions = "?Vcsvd:NqL:f:i:p:P:A:t:u:akKFnl:r:S:b:B:m:I:M:y";
static struct option longoptions[] = {
@@ -58,6 +59,7 @@ static struct option longoptions[] = {
{"nodetach", no_argument, (int *) 0, LA_NODETACH },
{"quit", no_argument, (int *) 0, LA_QUIT },
{"logfile", required_argument, (int *) 0, LA_LOGFILE },
+ {"syslog", no_argument, (int *) 0, LA_SYSLOG },
{"fetchmailrc",required_argument,(int *) 0, LA_RCFILE },
{"idfile", required_argument, (int *) 0, LA_IDFILE },
#ifdef linux
@@ -272,6 +274,10 @@ struct query *ctl; /* option record to be initialized */
yydebug = TRUE;
break;
+ case LA_SYSLOG:
+ use_syslog = TRUE;
+ break;
+
case '?':
case LA_HELP:
default:
@@ -285,6 +291,12 @@ struct query *ctl; /* option record to be initialized */
return(-1);
}
+ if (poll_interval == 0 && use_syslog)
+ {
+ fputs("The --syslog option is only valid with the --daemon option.\n", stderr);
+ return(-1);
+ }
+
if (errflag || ocount > 1) {
/* squawk if syntax errors were detected */
fputs("usage: fetchmail [options] [server ...]\n", stderr);
@@ -299,6 +311,7 @@ struct query *ctl; /* option record to be initialized */
fputs(" -N, --nodetach don't detach daemon process\n", stderr);
fputs(" -q, --quit kill daemon process\n", stderr);
fputs(" -L, --logfile specify logfile name\n", stderr);
+ fputs(" --syslog use syslog(3) for most messages when running as a daemon\n", stderr);
fputs(" -f, --fetchmailrc specify alternate run control file\n", stderr);
fputs(" -i, --idfile specify alternate UIDs file\n", stderr);
#ifdef linux
diff --git a/report.c b/report.c
index 19fb3f45..3e973c84 100644
--- a/report.c
+++ b/report.c
@@ -22,6 +22,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#endif
#include <stdio.h>
+#include <errno.h>
+#if defined(HAVE_SYSLOG)
+#include <syslog.h>
+#endif
+#if defined(HAVE_ALLOCA_H)
+#include <alloca.h>
+#endif
#if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC
# if __STDC__
@@ -43,6 +50,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
void exit ();
#endif
+#include "fetchmail.h"
+
#ifndef _
# define _(String) String
#endif
@@ -56,6 +65,11 @@ void (*error_print_progname) (
#endif
);
+/* Used by error_build() and error_complete() to accumulate partial messages. */
+static unsigned int partial_message_size = 0;
+static unsigned int partial_message_size_used = 0;
+static char *partial_message;
+
/* This variable is incremented each time `error' is called. */
unsigned int error_message_count;
@@ -112,40 +126,263 @@ error (status, errnum, message, va_alist)
va_list args;
#endif
- if (error_print_progname)
- (*error_print_progname) ();
+ /* If a partially built message exists, print it now so it's not lost. */
+ if (partial_message_size_used != 0)
+ {
+ partial_message_size_used = 0;
+ error (0, 0, "%s (message incomplete)", partial_message);
+ }
+
+#if defined(HAVE_SYSLOG)
+ if (use_syslog)
+ {
+ int priority;
+
+# ifdef VA_START
+ VA_START (args, message);
+# endif
+ priority = status? LOG_ALERT : errnum? LOG_ERR : LOG_INFO;
+
+ if (errnum)
+ {
+ char *msg = alloca (strlen (message) + 5);
+
+ strcpy (msg, message);
+ strcat (msg, ": %m");
+
+ errno = errnum;
+# ifdef VA_START
+ vsyslog (priority, msg, args);
+ va_end (args);
+# else
+ syslog (priority, msg, a1, a2, a3, a4, a5, a6, a7, a8);
+# endif
+ }
+ else
+ {
+# ifdef VA_START
+ vsyslog (priority, message, args);
+ va_end (args);
+# else
+ syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
+# endif
+ }
+ }
else
+#endif
{
- fflush (stdout);
- if ( *message == '\n' )
+ if (error_print_progname)
+ (*error_print_progname) ();
+ else
{
- fputc( '\n', stderr );
- ++message;
+ fflush (stdout);
+ if ( *message == '\n' )
+ {
+ fputc( '\n', stderr );
+ ++message;
+ }
+ fprintf (stderr, "%s: ", program_name);
}
- fprintf (stderr, "%s: ", program_name);
- }
#ifdef VA_START
- VA_START (args, message);
+ VA_START (args, message);
# if HAVE_VPRINTF || _LIBC
- vfprintf (stderr, message, args);
+ vfprintf (stderr, message, args);
# else
- _doprnt (message, args, stderr);
+ _doprnt (message, args, stderr);
# endif
- va_end (args);
+ va_end (args);
#else
- fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+ fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
#endif
+ if (errnum)
+ fprintf (stderr, ": %s", strerror (errnum));
+ putc ('\n', stderr);
+ fflush (stderr);
+ }
++error_message_count;
- if (errnum)
- fprintf (stderr, ": %s", strerror (errnum));
- putc ('\n', stderr);
- fflush (stderr);
if (status)
exit (status);
}
+/* Build an error message by appending MESSAGE, which is a printf-style
+ format string with optional args, to the existing error message (which may
+ be empty.) The completed error message is finally printed (and reset to
+ empty) by calling error_complete().
+ If an intervening call to error() occurs when a partially constructed
+ message exists, then, in an attempt to keep the messages in their proper
+ sequence, the partial message will be printed as-is (with a trailing newline)
+ before error() prints its message.
+/* VARARGS */
+
+void
+#if defined(VA_START) && __STDC__
+error_build (const char *message, ...)
+#else
+error_build (message, va_alist)
+ char *message;
+ va_dcl
+#endif
+{
+#ifdef VA_START
+ va_list args;
+ int n;
+#endif
+
+ /* Make an initial guess for the size of any single message fragment. */
+ if (partial_message_size == 0)
+ {
+ partial_message_size_used = 0;
+ partial_message_size = 512;
+ partial_message = xmalloc (partial_message_size);
+ }
+ else
+ if (partial_message_size - partial_message_size_used < 256)
+ {
+ partial_message_size += 512;
+ partial_message = xrealloc (partial_message, partial_message_size);
+ }
+
+#if defined(VA_START) && (HAVE_VSNPRINTF || _LIBC)
+ VA_START (args, message);
+ for ( ; ; )
+ {
+ n = vsnprintf (partial_message + partial_message_size_used,
+ partial_message_size - partial_message_size_used,
+ message, args);
+
+ if (n < partial_message_size - partial_message_size_used)
+ {
+ partial_message_size_used += n;
+ break;
+ }
+
+ partial_message_size += 512;
+ partial_message = xrealloc (partial_message, partial_message_size);
+ }
+ va_end (args);
+#else
+#if HAVE_SNPRINTF
+ for ( ; ; )
+ {
+ n = snprintf (partial_message + partial_message_size_used,
+ partial_message_size - partial_message_size_used,
+ message, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ if (n < partial_message_size - partial_message_size_used)
+ {
+ partial_message_size_used += n;
+ break;
+ }
+
+ partial_message_size += 512;
+ partial_message = xrealloc (partial_message, partial_message_size);
+ }
+#else
+ sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ /* Attempt to catch memory overwrites... */
+ if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
+ {
+ partial_message_size_used = 0;
+ error (PS_UNDEFINED, 0, "partial error message buffer overflow");
+ }
+#endif
+#endif
+}
+
+/* Complete an error message by appending MESSAGE, which is a printf-style
+ format string with optional args, to the existing error message (which may
+ be empty.) The completed error message is then printed (and reset to
+ empty.)
+/* VARARGS */
+
+void
+#if defined(VA_START) && __STDC__
+error_complete (int status, int errnum, const char *message, ...)
+#else
+error_complete (status, errnum, message, va_alist)
+ int status;
+ int errnum;
+ char *message;
+ va_dcl
+#endif
+{
+#ifdef VA_START
+ va_list args;
+ int n;
+#endif
+
+ /* Make an initial guess for the size of any single message fragment. */
+ if (partial_message_size == 0)
+ {
+ partial_message_size_used = 0;
+ partial_message_size = 512;
+ partial_message = xmalloc (partial_message_size);
+ }
+ else
+ if (partial_message_size - partial_message_size_used < 256)
+ {
+ partial_message_size += 512;
+ partial_message = xrealloc (partial_message, partial_message_size);
+ }
+
+#if defined(VA_START) && (HAVE_VSNPRINTF || _LIBC)
+ VA_START (args, message);
+ for ( ; ; )
+ {
+ n = vsnprintf (partial_message + partial_message_size_used,
+ partial_message_size - partial_message_size_used,
+ message, args);
+
+ if (n < partial_message_size - partial_message_size_used)
+ {
+ partial_message_size_used += n;
+ break;
+ }
+
+ partial_message_size += 512;
+ partial_message = xrealloc (partial_message, partial_message_size);
+ }
+ va_end (args);
+#else
+#if HAVE_SNPRINTF
+ for ( ; ; )
+ {
+ n = snprintf (partial_message + partial_message_size_used,
+ partial_message_size - partial_message_size_used,
+ message, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ if (n < partial_message_size - partial_message_size_used)
+ {
+ partial_message_size_used += n;
+ break;
+ }
+
+ partial_message_size += 512;
+ partial_message = xrealloc (partial_message, partial_message_size);
+ }
+#else
+ sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ /* Attempt to catch memory overwrites... */
+ if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
+ {
+ partial_message_size_used = 0;
+ error (PS_UNDEFINED, 0, "partial error message buffer overflow");
+ }
+#endif
+#endif
+
+ /* Finally... print it. */
+ if (partial_message_size_used != 0)
+ {
+ partial_message_size_used = 0;
+ error (status, errnum, "%s", partial_message);
+ }
+}
+
/* Sometimes we want to have at most one error per line. This
variable controls whether this mode is selected or not. */
int error_one_per_line;
diff --git a/xmalloc.c b/xmalloc.c
index 3c231294..8e085b0c 100644
--- a/xmalloc.c
+++ b/xmalloc.c
@@ -30,6 +30,17 @@ xmalloc (int n)
return(p);
}
+XMALLOCTYPE *
+xrealloc (XMALLOCTYPE *p, int n)
+{
+ if (p == 0)
+ return xmalloc (n);
+ p = (XMALLOCTYPE *) realloc(p, n);
+ if (p == (XMALLOCTYPE *) 0)
+ error(PS_UNDEFINED, errno, "realloc failed");
+ return p;
+}
+
char *xstrdup(const char *s)
{
char *p;