]> Pileus Git - ~andy/fetchmail/commitdiff
Dave Bodenstab's error changes.
authorEric S. Raymond <esr@thyrsus.com>
Mon, 30 Dec 1996 18:27:14 +0000 (18:27 -0000)
committerEric S. Raymond <esr@thyrsus.com>
Mon, 30 Dec 1996 18:27:14 +0000 (18:27 -0000)
svn path=/trunk/; revision=705

NEWS
acconfig.h
configure.in
driver.c
fetchmail.c
fetchmail.h
fetchmail.man
options.c
report.c
xmalloc.c

diff --git a/NEWS b/NEWS
index f315dbd79bb7b3906e8113201e6883b1a6e83375..6dae6bf940ddf9f1e9518f93fe3126b0a79c5915 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,17 +1,19 @@
                            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)
 
index d6a1399b88f94d219977f800f701c22bf7a6b208..9f8434d08b9dfb1e5c3395d29951fffb0439dc64 100644 (file)
@@ -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
 
 \f
 /* Leave that blank line there!!  Autoheader needs it.
index d988c62020ffb9539320cfdd86d2da4460432821..6dea56c5c02348707bc67853c92fda5b47f18125 100644 (file)
@@ -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
 
index 459bfd81fecc7f344216eeab0c0a22f7be8c543b..ce09c8e17993ba5bd559d32e40ff674d86681f91 100644 (file)
--- 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)
index 846c4ae750ec9f4ca93d428051d7d6823c208400..37ceb0d8b483e8d0622760046da3e50b9bd5ed8b 100644 (file)
@@ -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]);
                }
            }
 
index 994bc690c6533f4a8aab5b00571865a4c8405ff6..905bc21151093dffca50f11f3be300722b23ff3b 100644 (file)
@@ -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 *);
index 1385bf78b8e36dff21b6428352d4b8f2e49a1e53..a6ea4142add024249860ecf9e58190b7cc177349 100644 (file)
@@ -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
index 4bbc593f6beb469b175fbb0fd6bdffce6f87602a..4c02d584b3ca3f063064aeb5e69adb22f38578b0 100644 (file)
--- a/options.c
+++ b/options.c
 #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
index 19fb3f4598f695e9df411959df1691549789829c..3e973c840f403e414a246e113157f5dcef867e65 100644 (file)
--- 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);
 }
 \f
+/* 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
+}
+\f
+/* 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);
+    }
+}
+\f
 /* 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;
index 3c2312949d9154379642e2e96ea07fdf74b69e3e..8e085b0c85f1e30903dfe3672c343c0aa3fca8b7 100644 (file)
--- 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;