Sync syslogd with FreBSD:
authorPeter Avalos <pavalos@theshell.com>
Sun, 15 Mar 2009 10:28:51 +0000 (00:28 -1000)
committerPeter Avalos <pavalos@theshell.com>
Tue, 7 Apr 2009 07:09:58 +0000 (21:09 -1000)
* Add a flag, -T, that tells syslogd to always replace the timestamp on
messages from the network.  This option lets us replace timestamps that
are correctly formatted but wrong.

* Allow comment to be placed at the end of a configuration line.

* Add a -8 switch to syslogd to prevent it from mangling 8-bit data.

* Open ctty in non-blocking mode to avoid hangs during open and close.

* Handle "*" as a priority properly.

* Dynamically determine length vs. hardcoding it.

* Free the previous message buffer (f_prevline) only after logging all
the messages and just before the process exit.  Also check f_prevline for
NULL before using it.

* Add the ability to log to an arbitrary udp port as well as the
standard syslog port.

* Currently, if writing out a log entry fails, we unlink that log entry
from our internal list of logfiles. So if writev(2) fails for potentially
transient errors like ENOSPC, syslogd requires a restart, even if the
filesystem has purged.  This change allows syslogd to ignore ENOSPC
space errors, so that when the filesystem is cleaned up, syslogd will
automatically start logging again without requiring the reset.
This makes syslogd(8) a bit more reliable.

* Add -C option which tells syslogd(8) to create log files if they don't
exist.

* Add cases for ENOBUFS and ENETDOWN. We need to make sure that we
catch all transient errors. This fixes situations where transient
error conditions such as network interfaces losing carrier signals
or the system running out of mbufs would result in the permanent
removal of forwarding syslog messages.

* Add -S option which allows to change the pathname of the privileged
socket /var/run/logpriv.

* Check that supplied facility is not bigger than LOG_NFACILITIES.

* Allow ':' and '%' in hostname specifications so that we can specify
IPv6 addresses and scope IDs.

* Protect against local flooder of /var/run/log. Do not loop forever in
syslog(3) if we are a priveleged program (sshd, su, etc.).

  - Make syslogd open an additional socket /var/run/logpriv, with 0600
    permissions.
  - In libc, try to use this socket.
  - Do not loop forever if we are using this socket

* Use stailqueue for sockets instead of socket buffer. Thus remove
limit for 20 sockets.

* Add possibility to specify file mode for sockets created with '-l'.

* Check that socket name in '-l' is absolute.

* Make syslog(3) thread safe.

lib/libc/gen/syslog.c
sys/sys/syslog.h
usr.sbin/syslogd/Makefile
usr.sbin/syslogd/syslog.conf.5
usr.sbin/syslogd/syslogd.8
usr.sbin/syslogd/syslogd.c

index 21e0982..0369f76 100644 (file)
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
@@ -31,7 +27,7 @@
  * SUCH DAMAGE.
  *
  * @(#)syslog.c        8.5 (Berkeley) 4/29/95
- * $FreeBSD: src/lib/libc/gen/syslog.c,v 1.21.2.3 2002/11/18 11:49:55 ru Exp $
+ * $FreeBSD: src/lib/libc/gen/syslog.c,v 1.39 2007/01/09 00:27:55 imp Exp $
  * $DragonFly: src/lib/libc/gen/syslog.c,v 1.9 2005/11/19 22:32:53 swildner Exp $
  */
 
 #include <errno.h>
 #include <fcntl.h>
 #include <paths.h>
+#include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
-#include "un-namespace.h"
 
 #include <stdarg.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
 
 static int     LogFile = -1;           /* fd for log */
-static int     connected;              /* have done connect */
+static int     status;                 /* connection status */
 static int     opened;                 /* have done openlog() */
 static int     LogStat = 0;            /* status bits, set by openlog() */
 static const char *LogTag = NULL;      /* string to tag the entry with */
 static int     LogFacility = LOG_USER; /* default facility code */
 static int     LogMask = 0xff;         /* mask of priorities to be logged */
-
-static void    disconnectlog (void); /* disconnect from syslogd */
-static void    connectlog (void);      /* (re)connect to syslogd */
+static pthread_mutex_t syslog_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#define        THREAD_LOCK()                                                   \
+       do {                                                            \
+               if (__isthreaded) _pthread_mutex_lock(&syslog_mutex);   \
+       } while(0)
+#define        THREAD_UNLOCK()                                                 \
+       do {                                                            \
+               if (__isthreaded) _pthread_mutex_unlock(&syslog_mutex); \
+       } while(0)
+
+static void    disconnectlog(void); /* disconnect from syslogd */
+static void    connectlog(void);       /* (re)connect to syslogd */
+static void    openlog_unlocked(const char *, int, int);
+
+enum {
+       NOCONN = 0,
+       CONNDEF,
+       CONNPRIV,
+};
 
 /*
  * Format of the magic cookie passed through the stdio hook
@@ -94,7 +110,7 @@ writehook(void *cookie, const char *buf, int len)
                h->base += len;
                h->left -= len;
        }
-       return 0;
+       return len;
 }
 
 /*
@@ -118,7 +134,7 @@ vsyslog(int pri, const char *fmt, va_list ap)
        char ch, *p;
        time_t now;
        int fd, saved_errno;
-       char *stdp, tbuf[2048], fmt_cpy[1024], timbuf[26];
+       char *stdp, tbuf[2048], fmt_cpy[1024], timbuf[26], errstr[64];
        FILE *fp, *fmt_fp;
        struct bufcookie tbuf_cookie;
        struct bufcookie fmt_cookie;
@@ -133,11 +149,15 @@ vsyslog(int pri, const char *fmt, va_list ap)
                pri &= LOG_PRIMASK|LOG_FACMASK;
        }
 
+       saved_errno = errno;
+
+       THREAD_LOCK();
+
        /* Check priority against setlogmask values. */
-       if (!(LOG_MASK(LOG_PRI(pri)) & LogMask))
+       if (!(LOG_MASK(LOG_PRI(pri)) & LogMask)) {
+               THREAD_UNLOCK();
                return;
-
-       saved_errno = errno;
+       }
 
        /* Set default facility if none specified. */
        if ((pri & LOG_FACMASK) == 0)
@@ -147,8 +167,10 @@ vsyslog(int pri, const char *fmt, va_list ap)
        tbuf_cookie.base = tbuf;
        tbuf_cookie.left = sizeof(tbuf);
        fp = fwopen(&tbuf_cookie, writehook);
-       if (fp == NULL)
+       if (fp == NULL) {
+               THREAD_UNLOCK();
                return;
+       }
 
        /* Build the message. */
        time(&now);
@@ -160,7 +182,7 @@ vsyslog(int pri, const char *fmt, va_list ap)
                stdp = tbuf + (sizeof(tbuf) - tbuf_cookie.left);
        }
        if (LogTag == NULL)
-               LogTag = getprogname();
+               LogTag = _getprogname();
        if (LogTag != NULL)
                fprintf(fp, "%s", LogTag);
        if (LogStat & LOG_PID)
@@ -178,16 +200,28 @@ vsyslog(int pri, const char *fmt, va_list ap)
                fmt_fp = fwopen(&fmt_cookie, writehook);
                if (fmt_fp == NULL) {
                        fclose(fp);
+                       THREAD_UNLOCK();
                        return;
                }
 
-               /* Substitute error message for %m. */
-               for ( ; (ch = *fmt); ++fmt)
+               /*
+                * Substitute error message for %m.  Be careful not to
+                * molest an escaped percent "%%m".  We want to pass it
+                * on untouched as the format is later parsed by vfprintf.
+                */
+               for ( ; (ch = *fmt); ++fmt) {
                        if (ch == '%' && fmt[1] == 'm') {
                                ++fmt;
-                               fputs(strerror(saved_errno), fmt_fp);
-                       } else
+                               strerror_r(saved_errno, errstr, sizeof(errstr));
+                               fputs(errstr, fmt_fp);
+                       } else if (ch == '%' && fmt[1] == '%') {
+                               ++fmt;
+                               fputc(ch, fmt_fp);
+                               fputc(ch, fmt_fp);
+                       } else {
                                fputc(ch, fmt_fp);
+                       }
+               }
 
                /* Null terminate if room */
                fputc(0, fmt_fp);
@@ -204,6 +238,10 @@ vsyslog(int pri, const char *fmt, va_list ap)
 
        cnt = sizeof(tbuf) - tbuf_cookie.left;
 
+       /* Remove a trailing newline */
+       if (tbuf[cnt - 1] == '\n')
+               cnt--;
+
        /* Output to stderr if requested. */
        if (LogStat & LOG_PERROR) {
                struct iovec iov[2];
@@ -219,19 +257,42 @@ vsyslog(int pri, const char *fmt, va_list ap)
 
        /* Get connected, output the message to the local logger. */
        if (!opened)
-               openlog(LogTag, LogStat | LOG_NDELAY, 0);
+               openlog_unlocked(LogTag, LogStat | LOG_NDELAY, 0);
        connectlog();
-       if (send(LogFile, tbuf, cnt, 0) >= 0)
-               return;
 
        /*
-        * If the send() failed, the odds are syslogd was restarted.
-        * Make one (only) attempt to reconnect to /dev/log.
+        * If the send() failed, there are two likely scenarios:
+        *  1) syslogd was restarted
+        *  2) /var/run/log is out of socket buffer space, which
+        *     in most cases means local DoS.
+        * We attempt to reconnect to /var/run/log to take care of
+        * case #1 and keep send()ing data to cover case #2
+        * to give syslogd a chance to empty its socket buffer.
+        *
+        * If we are working with a priveleged socket, then take
+        * only one attempt, because we don't want to freeze a
+        * critical application like su(1) or sshd(8).
+        *
         */
-       disconnectlog();
-       connectlog();
-       if (send(LogFile, tbuf, cnt, 0) >= 0)
+
+       if (send(LogFile, tbuf, cnt, 0) < 0) {
+               if (errno != ENOBUFS) {
+                       disconnectlog();
+                       connectlog();
+               }
+               do {
+                       _usleep(1);
+                       if (send(LogFile, tbuf, cnt, 0) >= 0) {
+                               THREAD_UNLOCK();
+                               return;
+                       }
+                       if (status == CONNPRIV)
+                               break;
+               } while (errno == ENOBUFS);
+       } else {
+               THREAD_UNLOCK();
                return;
+       }
 
        /*
         * Output the message to the console; try not to block
@@ -252,7 +313,11 @@ vsyslog(int pri, const char *fmt, va_list ap)
                _writev(fd, iov, 2);
                _close(fd);
        }
+
+       THREAD_UNLOCK();
 }
+
+/* Should be called with mutex acquired */
 static void
 disconnectlog(void)
 {
@@ -265,9 +330,10 @@ disconnectlog(void)
                _close(LogFile);
                LogFile = -1;
        }
-       connected = 0;                  /* retry connect */
+       status = NOCONN;                        /* retry connect */
 }
 
+/* Should be called with mutex acquired */
 static void
 connectlog(void)
 {
@@ -278,35 +344,49 @@ connectlog(void)
                        return;
                _fcntl(LogFile, F_SETFD, 1);
        }
-       if (LogFile != -1 && !connected) {
+       if (LogFile != -1 && status == NOCONN) {
                SyslogAddr.sun_len = sizeof(SyslogAddr);
                SyslogAddr.sun_family = AF_UNIX;
-               strncpy(SyslogAddr.sun_path, _PATH_LOG,
+
+               /*
+                * First try priveleged socket. If no success,
+                * then try default socket.
+                */
+               strncpy(SyslogAddr.sun_path, _PATH_LOG_PRIV,
                    sizeof SyslogAddr.sun_path);
-               connected = _connect(LogFile, (struct sockaddr *)&SyslogAddr,
-                       sizeof(SyslogAddr)) != -1;
+               if (_connect(LogFile, (struct sockaddr *)&SyslogAddr,
+                   sizeof(SyslogAddr)) != -1)
+                       status = CONNPRIV;
+
+               if (status == NOCONN) {
+                       strncpy(SyslogAddr.sun_path, _PATH_LOG,
+                           sizeof SyslogAddr.sun_path);
+                       if (_connect(LogFile, (struct sockaddr *)&SyslogAddr,
+                           sizeof(SyslogAddr)) != -1)
+                               status = CONNDEF;
+               }
 
-               if (!connected) {
+               if (status == NOCONN) {
                        /*
                         * Try the old "/dev/log" path, for backward
                         * compatibility.
                         */
                        strncpy(SyslogAddr.sun_path, _PATH_OLDLOG,
                            sizeof SyslogAddr.sun_path);
-                       connected = _connect(LogFile,
-                               (struct sockaddr *)&SyslogAddr,
-                               sizeof(SyslogAddr)) != -1;
+                       if (_connect(LogFile, (struct sockaddr *)&SyslogAddr,
+                           sizeof(SyslogAddr)) != -1)
+                               status = CONNDEF;
                }
 
-               if (!connected) {
+               if (status == NOCONN) {
                        _close(LogFile);
                        LogFile = -1;
                }
        }
 }
 
-void
-openlog(const char *ident, int logstat, int logfac)
+static void
+openlog_unlocked(const char *ident, int logstat, int logfac)
 {
        if (ident != NULL)
                LogTag = ident;
@@ -320,13 +400,24 @@ openlog(const char *ident, int logstat, int logfac)
        opened = 1;     /* ident and facility has been set */
 }
 
+void
+openlog(const char *ident, int logstat, int logfac)
+{
+       THREAD_LOCK();
+       openlog_unlocked(ident, logstat, logfac);
+       THREAD_UNLOCK();
+}
+
+
 void
 closelog(void)
 {
+       THREAD_LOCK();
        _close(LogFile);
        LogFile = -1;
        LogTag = NULL;
-       connected = 0;
+       status = NOCONN;
+       THREAD_UNLOCK();
 }
 
 /* setlogmask -- set the log mask level */
@@ -335,8 +426,10 @@ setlogmask(int pmask)
 {
        int omask;
 
+       THREAD_LOCK();
        omask = LogMask;
        if (pmask != 0)
                LogMask = pmask;
+       THREAD_UNLOCK();
        return (omask);
 }
index 2908173..6cb90dd 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*-
  * Copyright (c) 1982, 1986, 1988, 1993
  *     The Regents of the University of California.  All rights reserved.
  *
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
@@ -31,7 +27,7 @@
  * SUCH DAMAGE.
  *
  *     @(#)syslog.h    8.1 (Berkeley) 6/2/93
- * $FreeBSD: src/sys/sys/syslog.h,v 1.19.2.2 2001/05/29 13:15:08 dwmalone Exp $
+ * $FreeBSD: src/sys/sys/syslog.h,v 1.27 2009/03/14 19:07:25 das Exp $
  * $DragonFly: src/sys/sys/syslog.h,v 1.5 2006/12/23 00:27:03 swildner Exp $
  */
 
@@ -39,6 +35,7 @@
 #define _SYS_SYSLOG_H_
 
 #define        _PATH_LOG       "/var/run/log"
+#define        _PATH_LOG_PRIV  "/var/run/logpriv"
 #define        _PATH_OLDLOG    "/dev/log"      /* backward compatibility */
 
 /*
@@ -187,22 +184,19 @@ CODE facilitynames[] = {
  * places (<machine/varargs.h> and <machine/stdarg.h>), so if we include one
  * of them here we may collide with the utility's includes.  It's unreasonable
  * for utilities to have to include one of them to include syslog.h, so we get
- * __va_list from <machine/stdarg.h> and use it.
+ * __va_list from <sys/types.h> and use it.
  */
 #include <sys/cdefs.h>
-#ifndef _MACHINE_STDINT_H_
-#include <machine/stdint.h>
-#endif
-#ifndef _MACHINE_STDARG_H_
-#include <machine/stdarg.h>
-#endif
+#include <sys/types.h>
 
 __BEGIN_DECLS
-void   closelog (void);
-void   openlog (const char *, int, int);
-int    setlogmask (int);
-void   syslog (int, const char *, ...) __printflike(2, 3);
-void   vsyslog (int, const char *, __va_list) __printflike(2, 0);
+void   closelog(void);
+void   openlog(const char *, int, int);
+int    setlogmask(int);
+void   syslog(int, const char *, ...) __printflike(2, 3);
+#if __BSD_VISIBLE
+void   vsyslog(int, const char *, __va_list) __printflike(2, 0);
+#endif
 __END_DECLS
 
 #endif /* !_KERNEL */
index d76deb3..f2567e1 100644 (file)
@@ -1,18 +1,18 @@
 #      @(#)Makefile    8.1 (Berkeley) 6/6/93
-# $FreeBSD: src/usr.sbin/syslogd/Makefile,v 1.12 2004/02/05 22:44:25 ru Exp $
+# $FreeBSD: src/usr.sbin/syslogd/Makefile,v 1.14 2008/12/17 16:51:40 obrien Exp $
 # $DragonFly: src/usr.sbin/syslogd/Makefile,v 1.3 2004/08/09 20:11:19 dillon Exp $
-#
 
-.PATH: ${.CURDIR}/../../usr.bin/wall
+.PATH: ${.CURDIR}/../../usr.bin/wall ${.CURDIR}/../nscd
 
 PROG=  syslogd
 MAN=   syslog.conf.5 syslogd.8
-SRCS=  syslogd.c ttymsg.c
+SRCS=  pidfile.c syslogd.c ttymsg.c
 
 DPADD= ${LIBUTIL}
 LDADD= -lutil
 
-WARNS?=        1
-CFLAGS+=-DINET6 -I${.CURDIR}/../../usr.bin/wall
+WARNS?=        2
+CFLAGS+= -DINET6
+CFLAGS+= -I${.CURDIR}/../../usr.bin/wall
 
 .include <bsd.prog.mk>
index 4db1e27..b7b2b35 100644 (file)
@@ -9,10 +9,6 @@
 .\" 2. Redistributions in binary form must reproduce the above copyright
 .\"    notice, this list of conditions and the following disclaimer in the
 .\"    documentation and/or other materials provided with the distribution.
-.\" 3. All advertising materials mentioning features or use of this software
-.\"    must display the following acknowledgement:
-.\"    This product includes software developed by the University of
-.\"    California, Berkeley and its contributors.
 .\" 4. Neither the name of the University nor the names of its contributors
 .\"    may be used to endorse or promote products derived from this software
 .\"    without specific prior written permission.
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)syslog.conf.5      8.1 (Berkeley) 6/9/93
-.\" $FreeBSD: src/usr.sbin/syslogd/syslog.conf.5,v 1.35 2004/07/03 18:35:53 ru Exp $
+.\" $FreeBSD: src/usr.sbin/syslogd/syslog.conf.5,v 1.46 2008/12/23 17:39:24 trhodes Exp $
 .\" $DragonFly: src/usr.sbin/syslogd/syslog.conf.5,v 1.10 2008/04/20 21:14:39 swildner Exp $
 .\"
-.Dd June 9, 1993
+.Dd December 23, 2008
 .Dt SYSLOG.CONF 5
 .Os
 .Sh NAME
@@ -52,7 +48,7 @@ blocks of lines separated by
 .Em program
 and
 .Em hostname
-specifications (separations appear along on the line),
+specifications (separations appear alone on their lines),
 with each line containing two fields: the
 .Em selector
 field which specifies the types of messages and priorities to which the
@@ -99,9 +95,13 @@ are case insensitive.
 The
 .Em facility
 describes the part of the system generating the message, and is one of
-the following keywords: auth, authpriv, console, cron, daemon, ftp, kern,
-lpr, mail, mark, news, ntp, security, syslog, user, uucp and local0 through
-local7.
+the following keywords:
+.Cm auth , authpriv , console , cron , daemon , ftp , kern , lpr ,
+.Cm mail , mark , news , ntp , security , syslog , user , uucp ,
+and
+.Cm local0
+through
+.Cm local7 .
 These keywords (with the exception of mark) correspond to
 similar
 .Dq Dv LOG_
@@ -137,8 +137,10 @@ has the same meaning as
 The
 .Em level
 describes the severity of the message, and is a keyword from the
-following ordered list (higher to lower): emerg, alert, crit, err,
-warning, notice, info and debug.
+following ordered list (higher to lower):
+.Cm emerg , crit , alert , err , warning , notice , info
+and
+.Cm debug .
 These keywords correspond to
 similar
 .Dq Dv LOG_
@@ -242,7 +244,7 @@ for further descriptions of both the
 and
 .Em level
 keywords and their significance.
-It's preferred that selections be made on
+It is preferred that selections be made on
 .Em facility
 rather than
 .Em program ,
@@ -250,7 +252,7 @@ since the latter can easily vary in a networked environment.
 In some cases,
 though, an appropriate
 .Em facility
-simply doesn't exist.
+simply does not exist.
 .Pp
 If a received message matches the specified
 .Em facility
@@ -342,6 +344,10 @@ sign).
 Selected messages are forwarded to the
 .Xr syslogd 8
 program on the named host.
+If a port number is added after a colon
+.Pq Ql :\&
+then that port will be used as the destination port
+rather than the usual syslog port.
 .It
 A comma separated list of users.
 Selected messages are written to those users
@@ -381,7 +387,7 @@ Upon receipt of a
 .Dv SIGHUP ,
 .Xr syslogd 8
 will close the pipe to the process.
-If the process didn't exit
+If the process did not exit
 voluntarily, it will be sent a
 .Dv SIGTERM
 signal after a grace period of up to 60 seconds.
@@ -396,7 +402,7 @@ flowing quickly), this can be achieved by exiting after just one line of
 input.
 If necessary, a script wrapper can be written to this effect.
 .Pp
-Unless the command is a full pipeline, it's probably useful to
+Unless the command is a full pipeline, it is probably useful to
 start the command with
 .Em exec
 so that the invoking shell process does not wait for the command to
@@ -409,6 +415,20 @@ normally the superuser.
 Blank lines and lines whose first non-blank character is a hash
 .Pq Dq #
 character are ignored.
+If
+.Ql #
+is placed in the middle of the line, the
+.Ql #
+character and the rest of the line after it is ignored.
+To prevent special meaning, the
+.Ql #
+character may be escaped with
+.Ql \e ;
+in this case preceding
+.Ql \e
+is removed and
+.Ql #
+is treated as an ordinary character.
 .Sh IMPLEMENTATION NOTES
 The
 .Dq kern
@@ -435,7 +455,7 @@ A configuration file might appear as follows:
 # level notice or higher, and anything of level err or
 # higher to the console.
 # Don't log private authentication messages!
-*.err;kern.*;auth.notice;authpriv.none /dev/console
+*.err;kern.*;auth.notice;authpriv.none;mail.crit       /dev/console
 
 # Log anything (except mail) of level info or higher.
 # Don't log private authentication messages!
index 8e4e990..140c684 100644 (file)
@@ -9,10 +9,6 @@
 .\" 2. Redistributions in binary form must reproduce the above copyright
 .\"    notice, this list of conditions and the following disclaimer in the
 .\"    documentation and/or other materials provided with the distribution.
-.\" 3. All advertising materials mentioning features or use of this software
-.\"    must display the following acknowledgement:
-.\"    This product includes software developed by the University of
-.\"    California, Berkeley and its contributors.
 .\" 4. Neither the name of the University nor the names of its contributors
 .\"    may be used to endorse or promote products derived from this software
 .\"    without specific prior written permission.
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)syslogd.8  8.1 (Berkeley) 6/6/93
-.\" $FreeBSD: src/usr.sbin/syslogd/syslogd.8,v 1.51 2004/07/02 23:12:57 ru Exp $
+.\" $FreeBSD: src/usr.sbin/syslogd/syslogd.8,v 1.64 2008/12/07 18:45:30 trhodes Exp $
 .\" $DragonFly: src/usr.sbin/syslogd/syslogd.8,v 1.5 2006/05/26 19:39:41 swildner Exp $
 .\"
-.Dd November 24, 2001
+.Dd May 13, 2008
 .Dt SYSLOGD 8
 .Os
 .Sh NAME
 .Nd log systems messages
 .Sh SYNOPSIS
 .Nm
-.Op Fl 46Acdknosuv
+.Op Fl 468ACcdknosuv
 .Op Fl a Ar allowed_peer
 .Op Fl b Ar bind_address
 .Op Fl f Ar config_file
-.Op Fl l Ar path
+.Op Fl l Oo Ar mode : Oc Ns Ar path
 .Op Fl m Ar mark_interval
 .Op Fl P Ar pid_file
 .Op Fl p Ar log_socket
@@ -65,6 +61,23 @@ to use IPv4 addresses only.
 Force
 .Nm
 to use IPv6 addresses only.
+.It Fl 8
+Tells
+.Nm
+not to interfere with 8-bit data.  Normally
+.Nm
+will replace C1 control characters
+.Pq ISO 8859 and Unicode characters
+with their
+.Dq M- Ns Em x
+equivalent.
+Note, this option does not change the way
+.Nm
+alters control characters
+.Pq see Xr iscntrl 3 .
+They will always be replaced with their
+.Dq ^ Ns Em x
+equivalent.
 .It Fl A
 Ordinarily,
 .Nm
@@ -83,8 +96,9 @@ Multiple
 .Fl a
 options may be specified.
 .Pp
-.Ar Allowed_peer
-can be any of the following:
+The
+.Ar allowed_peer
+option may be any of the following:
 .Bl -tag -width "ipaddr/masklen[:service]XX"
 .It Xo
 .Sm off
@@ -162,6 +176,9 @@ option is also specified.
 Specify one specific IP address or hostname to bind to.
 If a hostname is specified,
 the IPv4 or IPv6 address which corresponds to it is used.
+.It Fl C
+Create log files that do not exist (permission is set to
+.Li 0600 ) .
 .It Fl c
 Disable the compression of repeated instances of the same line
 into a single line of the form
@@ -207,20 +224,31 @@ the default is
 Specify an alternative file in which to store the process ID.
 The default is
 .Pa /var/run/syslog.pid .
+.It Fl S
+Specify the pathname of an alternate log socket for privileged
+applications to be used instead; the default is
+.Pa /var/run/logpriv .
 .It Fl l
 Specify a location where
 .Nm
 should place an additional log socket.
-Up to 19 additional logging sockets can be specified.
 The primary use for this is to place additional log sockets in
 .Pa /var/run/log
 of various chroot filespaces.
+File permissions for socket can be specified in octal representation
+before socket name, delimited with a colon.
+Path to socket location must be absolute.
 .It Fl s
 Operate in secure mode.
 Do not log messages from remote machines.
 If
 specified twice, no network socket will be opened at all, which also
 disables logging to remote machines.
+.It Fl T
+Always use the local time and date for messages received from the network,
+instead of the timestamp field supplied in the message by the remote host.
+This is useful if some of the originating hosts can't keep time properly
+or are unable to generate a correct timestamp.
 .It Fl u
 Unique priority logging.
 Only log messages at the specified priority.
@@ -250,8 +278,10 @@ The
 .Nm
 utility reads messages from the
 .Ux
-domain socket
-.Pa /var/run/log ,
+domain sockets
+.Pa /var/run/log
+and
+.Pa /var/run/logpriv ,
 from an Internet domain socket specified in
 .Pa /etc/services ,
 and from the special device
@@ -280,9 +310,18 @@ include file
 .Pp
 For security reasons,
 .Nm
-will not append to log files that do not exist;
+will not append to log files that do not exist (unless
+.Fl C
+option is specified);
 therefore, they must be created manually before running
 .Nm .
+.Pp
+The date and time are taken from the received message.
+If the format of the timestamp field is incorrect,
+time obtained from the local host is used instead.
+This can be overriden by the
+.Fl T
+flag.
 .Sh FILES
 .Bl -tag -width /var/run/syslog.pid -compact
 .It Pa /etc/syslog.conf
@@ -293,6 +332,9 @@ default process ID file
 name of the
 .Ux
 domain datagram log socket
+.It Pa /var/run/logpriv
+.Ux
+socket for privileged applications
 .It Pa /dev/klog
 kernel log device
 .El
@@ -300,7 +342,8 @@ kernel log device
 .Xr logger 1 ,
 .Xr syslog 3 ,
 .Xr services 5 ,
-.Xr syslog.conf 5
+.Xr syslog.conf 5 ,
+.Xr newsyslog 8
 .Sh HISTORY
 The
 .Nm
@@ -330,7 +373,7 @@ option is therefore highly recommended.
 .Pp
 The
 .Fl a
-matching algorithm doesn't pretend to be very efficient; use of numeric
+matching algorithm does not pretend to be very efficient; use of numeric
 IP addresses is faster than domain name comparison.
 Since the allowed
 peer list is being walked linearly, peer groups where frequent messages
index b62d490..95a025d 100644 (file)
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
@@ -30,9 +26,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * @(#) Copyright (c) 1983, 1988, 1993, 1994 The Regents of the University of California.  All rights reserved.
  * @(#)syslogd.c       8.3 (Berkeley) 4/4/94
- * $FreeBSD: src/usr.sbin/syslogd/syslogd.c,v 1.130 2004/07/04 19:52:48 cperciva Exp $
+ * $FreeBSD: src/usr.sbin/syslogd/syslogd.c,v 1.163 2008/12/19 18:27:51 delphij Exp $
  * $DragonFly: src/usr.sbin/syslogd/syslogd.c,v 1.6 2007/08/09 02:17:46 dillon Exp $
  */
 
 
 #define        MAXLINE         1024            /* maximum line length */
 #define        MAXSVLINE       120             /* maximum saved line length */
-#define DEFUPRI                (LOG_USER|LOG_NOTICE)
-#define DEFSPRI                (LOG_KERN|LOG_CRIT)
-#define TIMERINTVL     30              /* interval for checking flush, mark */
-#define TTYMSGTIME     1               /* timeout passed to ttymsg */
+#define        DEFUPRI         (LOG_USER|LOG_NOTICE)
+#define        DEFSPRI         (LOG_KERN|LOG_CRIT)
+#define        TIMERINTVL      30              /* interval for checking flush, mark */
+#define        TTYMSGTIME      1               /* timeout passed to ttymsg */
 
 #include <sys/param.h>
 #include <sys/ioctl.h>
 #include "pathnames.h"
 #include "ttymsg.h"
 #include "../clog/clog.h"
+#include "../nscd/pidfile.h"
 
 #define SYSLOG_NAMES
 #include <sys/syslog.h>
 
-#ifdef NI_WITHSCOPEID
-static const int withscopeid = NI_WITHSCOPEID;
-#else
-static const int withscopeid;
-#endif
-
 const char     *ConfFile = _PATH_LOGCONF;
 const char     *PidFile = _PATH_LOGPID;
 const char     ctty[] = _PATH_CONSOLE;
@@ -123,23 +113,36 @@ const char        ring_magic[] = "CLOG";
 
 #define        dprintf         if (Debug) printf
 
-#define MAXUNAMES      20      /* maximum number of user names */
+#define        MAXUNAMES       20      /* maximum number of user names */
 
-#define MAXFUNIX       20
+/*
+ * Unix sockets.
+ * We have two default sockets, one with 666 permissions,
+ * and one for privileged programs.
+ */
+struct funix {
+       int                     s;
+       const char              *name;
+       mode_t                  mode;
+       STAILQ_ENTRY(funix)     next;
+};
+struct funix funix_secure =    { -1, _PATH_LOG_PRIV, S_IRUSR | S_IWUSR,
+                               { NULL } };
+struct funix funix_default =   { -1, _PATH_LOG, DEFFILEMODE,
+                               { &funix_secure } };
 
-int nfunix = 1;
-const char *funixn[MAXFUNIX] = { _PATH_LOG };
-int funix[MAXFUNIX];
+STAILQ_HEAD(, funix) funixes = { &funix_default,
+                               &(funix_secure.next.stqe_next) };
 
 /*
  * Flags to logmsg().
  */
 
-#define IGN_CONS       0x001   /* don't print on console */
-#define SYNC_FILE      0x002   /* do fsync on file after printing */
-#define ADDDATE                0x004   /* add a date to the message */
-#define MARK           0x008   /* this message is a mark */
-#define ISKERNEL       0x010   /* kernel generated message */
+#define        IGN_CONS        0x001   /* don't print on console */
+#define        SYNC_FILE       0x002   /* do fsync on file after printing */
+#define        ADDDATE         0x004   /* add a date to the message */
+#define        MARK            0x008   /* this message is a mark */
+#define        ISKERNEL        0x010   /* kernel generated message */
 
 /*
  * This structure represents the files that will have log
@@ -186,8 +189,8 @@ struct filed {
        int     f_prevcount;                    /* repetition cnt of prevline */
        u_int   f_repeatcount;                  /* number of "repeated" msgs */
        int     f_flags;                        /* file-specific flags */
-#define FFLAG_SYNC 0x01
-#define FFLAG_NEEDSYNC 0x02
+#define        FFLAG_SYNC 0x01
+#define        FFLAG_NEEDSYNC  0x02
 };
 
 /*
@@ -209,7 +212,7 @@ struct deadq_entry {
  * Processes on the dead queue will be terminated after that time.
  */
 
-#define DQ_TIMO_INIT   2
+#define         DQ_TIMO_INIT   2
 
 typedef struct deadq_entry *dq_t;
 
@@ -281,20 +284,24 @@ static int        family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */
 #else
 static int     family = PF_INET; /* protocol family (IPv4 only) */
 #endif
+static int     mask_C1 = 1;    /* mask characters from 0x80 - 0x9F */
 static int     send_to_all;    /* send message to all IPv4/IPv6 addresses */
 static int     use_bootfile;   /* log entire bootfile for every kern msg */
 static int     no_compress;    /* don't compress messages (1=pipes, 2=all) */
+static int     logflags = O_WRONLY|O_APPEND; /* flags used to open log files */
 
 static char    bootfile[MAXLINE+1]; /* booted kernel file */
 
 struct allowedpeer *AllowedPeers; /* List of allowed peers */
 static int     NumAllowed;     /* Number of entries in AllowedPeers */
+static int     RemoteAddDate;  /* Always set the date on remote messages */
 
 static int     UniquePriority; /* Only log specified priority? */
 static int     LogFacPri;      /* Put facility and priority in log message: */
                                /* 0=no, 1=numeric, 2=names */
 static int     KeepKernFac;    /* Keep remotely logged kernel facility */
 static int     needdofsync = 0; /* Are any file(s) waiting to be fsynced? */
+static struct pidfh *pfh;
 
 volatile sig_atomic_t MarkSet, WantDie;
 
@@ -311,14 +318,13 @@ static void       dofsync(void);
 static void    domark(int);
 static void    fprintlog(struct filed *, int, const char *);
 static int     *socksetup(int, const char *);
-static void    setsockbuffer(int);
 static void    init(int);
 static void    logerror(const char *);
 static void    logmsg(int, const char *, const char *, int);
 static void    log_deadchild(pid_t, int, const char *);
 static void    markit(void);
 static int     skip_message(const char *, const char *, int);
-static void    printline(const char *, char *);
+static void    printline(const char *, char *, int);
 static void    printsys(char *);
 static int     p_open(const char *, pid_t *);
 ssize_t                rbwrite(struct filed *, char *, size_t);
@@ -328,9 +334,10 @@ static void        reapchild(int);
 static void    usage(void);
 static int     validate(struct sockaddr *, const char *);
 static void    unmapped(struct sockaddr *);
-static void    wallmsg(struct filed *, struct iovec *);
+static void    wallmsg(struct filed *, struct iovec *, const int iovlen);
 static int     waitdaemon(int, int, int);
 static void    timedout(int);
+static void    double_rbuf(int);
 
 int
 main(int argc, char *argv[])
@@ -339,17 +346,18 @@ main(int argc, char *argv[])
        struct sockaddr_un sunx, fromunix;
        struct sockaddr_storage frominet;
        fd_set *fdsr = NULL;
-       FILE *fp;
        char line[MAXLINE + 1];
        const char *bindhostname, *hname;
        struct timeval tv, *tvp;
        struct sigaction sact;
+       struct funix *fx, *fx1;
        sigset_t mask;
-       pid_t ppid = 1;
+       pid_t ppid = 1, spid;
        socklen_t len;
 
        bindhostname = NULL;
-       while ((ch = getopt(argc, argv, "46Aa:b:cdf:kl:m:nop:P:suv")) != -1)
+       while ((ch = getopt(argc, argv, "468Aa:b:cCdf:kl:m:nop:P:sS:Tuv"))
+           != -1)
                switch (ch) {
                case '4':
                        family = PF_INET;
@@ -359,6 +367,9 @@ main(int argc, char *argv[])
                        family = PF_INET6;
                        break;
 #endif
+               case '8':
+                       mask_C1 = 0;
+                       break;
                case 'A':
                        send_to_all++;
                        break;
@@ -372,6 +383,9 @@ main(int argc, char *argv[])
                case 'c':
                        no_compress++;
                        break;
+               case 'C':
+                       logflags |= O_CREAT;
+                       break;
                case 'd':               /* debug */
                        Debug++;
                        break;
@@ -382,14 +396,42 @@ main(int argc, char *argv[])
                        KeepKernFac = 1;
                        break;
                case 'l':
-                       if (strlen(optarg) >= sizeof(sunx.sun_path))
-                               errx(1, "%s path too long, exiting", optarg);
-                       if (nfunix < MAXFUNIX)
-                               funixn[nfunix++] = optarg;
-                       else
-                               warnx("out of descriptors, ignoring %s",
-                                       optarg);
+                   {
+                       long    perml;
+                       mode_t  mode;
+                       char    *name, *ep;
+
+                       if (optarg[0] == '/') {
+                               mode = DEFFILEMODE;
+                               name = optarg;
+                       } else if ((name = strchr(optarg, ':')) != NULL) {
+                               *name++ = '\0';
+                               if (name[0] != '/')
+                                       errx(1, "socket name must be absolute "
+                                           "path");
+                               if (isdigit(*optarg)) {
+                                       perml = strtol(optarg, &ep, 8);
+                                   if (*ep || perml < 0 ||
+                                       perml & ~(S_IRWXU|S_IRWXG|S_IRWXO))
+                                           errx(1, "invalid mode %s, exiting",
+                                               optarg);
+                                   mode = (mode_t )perml;
+                               } else
+                                       errx(1, "invalid mode %s, exiting",
+                                           optarg);
+                       } else  /* doesn't begin with '/', and no ':' */
+                               errx(1, "can't parse path %s", optarg);
+
+                       if (strlen(name) >= sizeof(sunx.sun_path))
+                               errx(1, "%s path too long, exiting", name);
+                       if ((fx = malloc(sizeof(struct funix))) == NULL)
+                               errx(1, "malloc failed");
+                       fx->s = -1;
+                       fx->name = name;
+                       fx->mode = mode;
+                       STAILQ_INSERT_TAIL(&funixes, fx, next);
                        break;
+                  }
                case 'm':               /* mark interval */
                        MarkInterval = atoi(optarg) * 60;
                        break;
@@ -402,7 +444,7 @@ main(int argc, char *argv[])
                case 'p':               /* path */
                        if (strlen(optarg) >= sizeof(sunx.sun_path))
                                errx(1, "%s path too long, exiting", optarg);
-                       funixn[0] = optarg;
+                       funix_default.name = optarg;
                        break;
                case 'P':               /* path for alt. PID */
                        PidFile = optarg;
@@ -410,8 +452,16 @@ main(int argc, char *argv[])
                case 's':               /* no network mode */
                        SecureMode++;
                        break;
+               case 'S':               /* path for privileged originator */
+                       if (strlen(optarg) >= sizeof(sunx.sun_path))
+                               errx(1, "%s path too long, exiting", optarg);
+                       funix_secure.name = optarg;
+                       break;
+               case 'T':
+                       RemoteAddDate = 1;
+                       break;
                case 'u':               /* only log specified priority */
-                       UniquePriority++;
+                       UniquePriority++;
                        break;
                case 'v':               /* log facility and priority */
                        LogFacPri++;
@@ -422,10 +472,20 @@ main(int argc, char *argv[])
        if ((argc -= optind) != 0)
                usage();
 
+       pfh = pidfile_open(PidFile, 0600, &spid);
+       if (pfh == NULL) {
+               if (errno == EEXIST)
+                       errx(1, "syslogd already running, pid: %d", spid);
+               warn("cannot open pid file");
+       }
+
        if (!Debug) {
                ppid = waitdaemon(0, 0, 30);
-               if (ppid < 0)
-                       err(1, "could not become daemon");
+               if (ppid < 0) {
+                       warn("could not become daemon");
+                       pidfile_remove(pfh);
+                       exit(1);
+               }
        } else {
                setlinebuf(stdout);
        }
@@ -461,25 +521,27 @@ main(int argc, char *argv[])
 #ifndef SUN_LEN
 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
 #endif
-       for (i = 0; i < nfunix; i++) {
-               unlink(funixn[i]);
+       STAILQ_FOREACH_MUTABLE(fx, &funixes, next, fx1) {
+               unlink(fx->name);
                memset(&sunx, 0, sizeof(sunx));
-               sunx.sun_family = AF_UNIX;
-               strlcpy(sunx.sun_path, funixn[i], sizeof(sunx.sun_path));
-               funix[i] = socket(AF_UNIX, SOCK_DGRAM, 0);
-               if (funix[i] < 0 ||
-                   bind(funix[i], (struct sockaddr *)&sunx,
-                        SUN_LEN(&sunx)) < 0 ||
-                   chmod(funixn[i], 0666) < 0) {
+               sunx.sun_family = AF_LOCAL;
+               strlcpy(sunx.sun_path, fx->name, sizeof(sunx.sun_path));
+               fx->s = socket(PF_LOCAL, SOCK_DGRAM, 0);
+               if (fx->s < 0 ||
+                   bind(fx->s, (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 ||
+                   chmod(fx->name, fx->mode) < 0) {
                        snprintf(line, sizeof line,
-                                "cannot create %s", funixn[i]);
+                                       "cannot create %s", fx->name);
                        logerror(line);
-                       dprintf("cannot create %s (%d)\n", funixn[i], errno);
-                       if (i == 0)
+                       dprintf("cannot create %s (%d)\n", fx->name, errno);
+                       if (fx == &funix_default || fx == &funix_secure)
                                die(0);
+                       else {
+                               STAILQ_REMOVE(&funixes, fx, funix, next);
+                               continue;
+                       }
+                       double_rbuf(fx->s);
                }
-               if (funix[i] >= 0)
-                       setsockbuffer(funix[i]);
        }
        if (SecureMode <= 1)
                finet = socksetup(family, bindhostname);
@@ -506,11 +568,7 @@ main(int argc, char *argv[])
                dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
 
        /* tuck my process id away */
-       fp = fopen(PidFile, "w");
-       if (fp != NULL) {
-               fprintf(fp, "%d\n", getpid());
-               fclose(fp);
-       }
+       pidfile_write(pfh);
 
        dprintf("off & running....\n");
 
@@ -534,10 +592,9 @@ main(int argc, char *argv[])
                        fdsrmax = finet[i+1];
                }
        }
-       for (i = 0; i < nfunix; i++) {
-               if (funix[i] != -1 && funix[i] > fdsrmax)
-                       fdsrmax = funix[i];
-       }
+       STAILQ_FOREACH(fx, &funixes, next)
+               if (fx->s > fdsrmax)
+                       fdsrmax = fx->s;
 
        fdsr = (fd_set *)calloc(howmany(fdsrmax+1, NFDBITS),
            sizeof(fd_mask));
@@ -561,10 +618,8 @@ main(int argc, char *argv[])
                                        FD_SET(finet[i+1], fdsr);
                        }
                }
-               for (i = 0; i < nfunix; i++) {
-                       if (funix[i] != -1)
-                               FD_SET(funix[i], fdsr);
-               }
+               STAILQ_FOREACH(fx, &funixes, next)
+                       FD_SET(fx->s, fdsr);
 
                i = select(fdsrmax+1, fdsr, NULL, NULL,
                    needdofsync ? &tv : tvp);
@@ -597,20 +652,20 @@ main(int argc, char *argv[])
                                                hname = cvthname((struct sockaddr *)&frominet);
                                                unmapped((struct sockaddr *)&frominet);
                                                if (validate((struct sockaddr *)&frominet, hname))
-                                                       printline(hname, line);
+                                                       printline(hname, line, RemoteAddDate ? ADDDATE : 0);
                                        } else if (l < 0 && errno != EINTR)
                                                logerror("recvfrom inet");
                                }
                        }
                }
-               for (i = 0; i < nfunix; i++) {
-                       if (funix[i] != -1 && FD_ISSET(funix[i], fdsr)) {
+               STAILQ_FOREACH(fx, &funixes, next) {
+                       if (FD_ISSET(fx->s, fdsr)) {
                                len = sizeof(fromunix);
-                               l = recvfrom(funix[i], line, MAXLINE, 0,
+                               l = recvfrom(fx->s, line, MAXLINE, 0,
                                    (struct sockaddr *)&fromunix, &len);
                                if (l > 0) {
                                        line[l] = '\0';
-                                       printline(LocalHostName, line);
+                                       printline(LocalHostName, line, 0);
                                } else if (l < 0 && errno != EINTR)
                                        logerror("recvfrom unix");
                        }
@@ -650,9 +705,9 @@ usage(void)
 {
 
        fprintf(stderr, "%s\n%s\n%s\n%s\n",
-               "usage: syslogd [-46Acdknosuv] [-a allowed_peer]",
-               "               [-b bind address] [-f config_file]",
-               "               [-l log_socket] [-m mark_interval]",
+               "usage: syslogd [-468ACcdknosTuv] [-a allowed_peer]",
+               "               [-b bind_address] [-f config_file]",
+               "               [-l [mode:]path] [-m mark_interval]",
                "               [-P pid_file] [-p log_socket]");
        exit(1);
 }
@@ -662,7 +717,7 @@ usage(void)
  * on the appropriate log files.
  */
 static void
-printline(const char *hname, char *msg)
+printline(const char *hname, char *msg, int flags)
 {
        char *p, *q;
        long n;
@@ -695,7 +750,7 @@ printline(const char *hname, char *msg)
 
        while ((c = (unsigned char)*p++) != '\0' &&
            q < &line[sizeof(line) - 4]) {
-               if ((c & 0x80) && c < 0xA0) {
+               if (mask_C1 && (c & 0x80) && c < 0xA0) {
                        c &= 0x7F;
                        *q++ = 'M';
                        *q++ = '-';
@@ -715,7 +770,7 @@ printline(const char *hname, char *msg)
        }
        *q = '\0';
 
-       logmsg(pri, line, hname, 0);
+       logmsg(pri, line, hname, flags);
 }
 
 /*
@@ -749,7 +804,7 @@ readklog(void)
                        printsys(p);
                        len = 0;
                }
-               if (len > 0) 
+               if (len > 0)
                        memmove(line, p, len + 1);
        }
        if (len > 0)
@@ -798,7 +853,8 @@ static time_t       now;
  * based on the specification.
  */
 static int
-skip_message(const char *name, const char *spec, int checkcase) {
+skip_message(const char *name, const char *spec, int checkcase)
+{
        const char *s;
        char prev, next;
        int exclude = 0;
@@ -882,12 +938,19 @@ logmsg(int pri, const char *msg, const char *from, int flags)
                fac = LOG_NFACILITIES;
        else
                fac = LOG_FAC(pri);
+
+       /* Check maximum facility number. */
+       if (fac > LOG_NFACILITIES) {
+               sigsetmask(omask);
+               return;
+       }
+
        prilev = LOG_PRI(pri);
 
        /* extract program name */
        for (i = 0; i < NAME_MAX; i++) {
                if (!isprint(msg[i]) || msg[i] == ':' || msg[i] == '[' ||
-                   msg[i] == '/')
+                   msg[i] == '/' || isspace(msg[i]))
                        break;
                prog[i] = msg[i];
        }
@@ -904,7 +967,11 @@ logmsg(int pri, const char *msg, const char *from, int flags)
        /* log the message to the particular outputs */
        if (!Initialized) {
                f = &consfile;
-               f->f_file = open(ctty, O_WRONLY, 0);
+               /*
+                * Open in non-blocking mode to avoid hangs during open
+                * and close(waiting for the port to drain).
+                */
+               f->f_file = open(ctty, O_WRONLY | O_NONBLOCK, 0);
 
                if (f->f_file >= 0) {
                        strlcpy(f->f_lasttime, timestamp,
@@ -945,7 +1012,7 @@ logmsg(int pri, const char *msg, const char *from, int flags)
                 */
                if (no_compress - (f->f_type != F_PIPE) < 1 &&
                    (flags & MARK) == 0 && msglen == f->f_prevlen &&
-                   !strcmp(msg, f->f_prevline) &&
+                   f->f_prevline && !strcmp(msg, f->f_prevline) &&
                    !strcasecmp(from, f->f_prevhost)) {
                        strlcpy(f->f_lasttime, timestamp,
                                sizeof(f->f_lasttime));
@@ -971,8 +1038,7 @@ logmsg(int pri, const char *msg, const char *from, int flags)
                        f->f_prevpri = pri;
                        strlcpy(f->f_lasttime, timestamp,
                                sizeof(f->f_lasttime));
-                       strlcpy(f->f_prevhost, from,
-                           sizeof(f->f_prevhost));
+                       strlcpy(f->f_prevhost, from, sizeof(f->f_prevhost));
                        if (msglen < MAXSVLINE) {
                                f->f_prevlen = msglen;
                                strlcpy(f->f_prevline, msg, sizeof(f->f_prevline));
@@ -1001,10 +1067,11 @@ dofsync(void)
        }
 }
 
+#define IOV_SIZE 7
 static void
 fprintlog(struct filed *f, int flags, const char *msg)
 {
-       struct iovec iov[7];
+       struct iovec iov[IOV_SIZE];
        struct iovec *v;
        struct addrinfo *r;
        int i, l, lsent = 0;
@@ -1015,9 +1082,14 @@ fprintlog(struct filed *f, int flags, const char *msg)
        v = iov;
        if (f->f_type == F_WALL) {
                v->iov_base = greetings;
+               /* The time displayed is not synchornized with the other log
+                * destinations (like messages).  Following fragment was using
+                * ctime(&now), which was updating the time every 30 sec.
+                * With f_lasttime, time is synchronized correctly.
+                */
                v->iov_len = snprintf(greetings, sizeof greetings,
                    "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
-                   f->f_prevhost, ctime(&now));
+                   f->f_prevhost, f->f_lasttime);
                if (v->iov_len > 0)
                        v++;
                v->iov_base = nul;
@@ -1025,7 +1097,7 @@ fprintlog(struct filed *f, int flags, const char *msg)
                v++;
        } else {
                v->iov_base = f->f_lasttime;
-               v->iov_len = 15;
+               v->iov_len = strlen(f->f_lasttime);
                v++;
                v->iov_base = space;
                v->iov_len = 1;
@@ -1069,7 +1141,7 @@ fprintlog(struct filed *f, int flags, const char *msg)
                v->iov_base = fp_buf;
                v->iov_len = strlen(fp_buf);
        } else {
-               v->iov_base = nul;
+               v->iov_base = nul;
                v->iov_len = 0;
        }
        v++;
@@ -1093,9 +1165,11 @@ fprintlog(struct filed *f, int flags, const char *msg)
                v->iov_base = repbuf;
                v->iov_len = snprintf(repbuf, sizeof repbuf,
                    "last message repeated %d times", f->f_prevcount);
-       } else {
+       } else if (f->f_prevline) {
                v->iov_base = f->f_prevline;
                v->iov_len = f->f_prevlen;
+       } else {
+               return;
        }
        v++;
 
@@ -1103,12 +1177,19 @@ fprintlog(struct filed *f, int flags, const char *msg)
        f->f_time = now;
 
        switch (f->f_type) {
+               int port;
        case F_UNUSED:
                dprintf("\n");
                break;
 
        case F_FORW:
-               dprintf(" %s\n", f->f_un.f_forw.f_hname);
+               port = (int)ntohs(((struct sockaddr_in *)
+                           (f->f_un.f_forw.f_addr->ai_addr))->sin_port);
+               if (port != 514) {
+                       dprintf(" %s:%d\n", f->f_un.f_forw.f_hname, port);
+               } else {
+                       dprintf(" %s\n", f->f_un.f_forw.f_hname);
+               }
                /* check for local vs remote messages */
                if (strcasecmp(f->f_prevhost, LocalHostName))
                        l = snprintf(line, sizeof line - 1,
@@ -1127,20 +1208,20 @@ fprintlog(struct filed *f, int flags, const char *msg)
                if (finet) {
                        for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) {
                                for (i = 0; i < *finet; i++) {
-#if 0 
+#if 0
                                        /*
                                         * should we check AF first, or just
                                         * trial and error? FWD
                                         */
                                        if (r->ai_family ==
-                                           address_family_of(finet[i+1])) 
+                                           address_family_of(finet[i+1]))
 #endif
                                        lsent = sendto(finet[i+1], line, l, 0,
                                            r->ai_addr, r->ai_addrlen);
-                                       if (lsent == l) 
+                                       if (lsent == l)
                                                break;
                                }
-                               if (lsent == l && !send_to_all) 
+                               if (lsent == l && !send_to_all)
                                        break;
                        }
                        dprintf("lsent/l: %d/%d\n", lsent, l);
@@ -1149,6 +1230,8 @@ fprintlog(struct filed *f, int flags, const char *msg)
                                logerror("sendto");
                                errno = e;
                                switch (errno) {
+                               case ENOBUFS:
+                               case ENETDOWN:
                                case EHOSTUNREACH:
                                case EHOSTDOWN:
                                        break;
@@ -1173,12 +1256,19 @@ fprintlog(struct filed *f, int flags, const char *msg)
                dprintf(" %s\n", f->f_un.f_fname);
                v->iov_base = lf;
                v->iov_len = 1;
-               if (writev(f->f_file, iov, 7) < 0) {
-                       int e = errno;
-                       close(f->f_file);
-                       f->f_type = F_UNUSED;
-                       errno = e;
-                       logerror(f->f_un.f_fname);
+               if (writev(f->f_file, iov, IOV_SIZE) < 0) {
+                       /*
+                        * If writev(2) fails for potentially transient errors
+                        * like the filesystem being full, ignore it.
+                        * Otherwise remove this logfile from the list.
+                        */
+                       if (errno != ENOSPC) {
+                               int e = errno;
+                               close(f->f_file);
+                               f->f_type = F_UNUSED;
+                               errno = e;
+                               logerror(f->f_un.f_fname);
+                       }
                } else if ((flags & SYNC_FILE) && (f->f_flags & FFLAG_SYNC)) {
                        f->f_flags |= FFLAG_NEEDSYNC;
                        needdofsync = 1;
@@ -1187,7 +1277,7 @@ fprintlog(struct filed *f, int flags, const char *msg)
 
        case F_RING:
                dprintf(" %s\n", f->f_un.f_ring.f_rname);
-               v->iov_base = "\n";
+               v->iov_base = lf;
                v->iov_len = 1;
                if (rbwritev(f, iov, 7) == -1) {
                        int e = errno;
@@ -1212,7 +1302,7 @@ fprintlog(struct filed *f, int flags, const char *msg)
                                break;
                        }
                }
-               if (writev(f->f_file, iov, 7) < 0) {
+               if (writev(f->f_file, iov, IOV_SIZE) < 0) {
                        int e = errno;
                        close(f->f_file);
                        if (f->f_un.f_pipe.f_pid > 0)
@@ -1237,7 +1327,7 @@ fprintlog(struct filed *f, int flags, const char *msg)
                v->iov_len = 2;
 
                errno = 0;      /* ttymsg() only sometimes returns an errno */
-               if ((msgret = ttymsg(iov, 7, f->f_un.f_fname, 10))) {
+               if ((msgret = ttymsg(iov, IOV_SIZE, f->f_un.f_fname, 10))) {
                        f->f_type = F_UNUSED;
                        logerror(msgret);
                }
@@ -1248,12 +1338,11 @@ fprintlog(struct filed *f, int flags, const char *msg)
                dprintf("\n");
                v->iov_base = crlf;
                v->iov_len = 2;
-               wallmsg(f, iov);
+               wallmsg(f, iov, IOV_SIZE);
                break;
        }
        f->f_prevcount = 0;
-       if (msg)
-               free(wmsg);
+       free(wmsg);
 }
 
 /*
@@ -1263,7 +1352,7 @@ fprintlog(struct filed *f, int flags, const char *msg)
  *     world, or a list of approved users.
  */
 static void
-wallmsg(struct filed *f, struct iovec *iov)
+wallmsg(struct filed *f, struct iovec *iov, const int iovlen)
 {
        static int reenter;                     /* avoid calling ourselves */
        FILE *uf;
@@ -1287,7 +1376,8 @@ wallmsg(struct filed *f, struct iovec *iov)
                strncpy(line, ut.ut_line, sizeof(line) - 1);
                line[sizeof(line) - 1] = '\0';
                if (f->f_type == F_WALL) {
-                       if ((p = ttymsg(iov, 7, line, TTYMSGTIME)) != NULL) {
+                       if ((p = ttymsg(iov, iovlen, line, TTYMSGTIME)) !=
+                           NULL) {
                                errno = 0;      /* already in msg */
                                logerror(p);
                        }
@@ -1299,8 +1389,8 @@ wallmsg(struct filed *f, struct iovec *iov)
                                break;
                        if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
                            UT_NAMESIZE)) {
-                               if ((p = ttymsg(iov, 7, line, TTYMSGTIME))
-                                                               != NULL) {
+                               if ((p = ttymsg(iov, iovlen, line, TTYMSGTIME))
+                                   != NULL) {
                                        errno = 0;      /* already in msg */
                                        logerror(p);
                                }
@@ -1355,8 +1445,7 @@ cvthname(struct sockaddr *f)
 
        error = getnameinfo((struct sockaddr *)f,
                            ((struct sockaddr *)f)->sa_len,
-                           ip, sizeof ip, NULL, 0,
-                           NI_NUMERICHOST | withscopeid);
+                           ip, sizeof ip, NULL, 0, NI_NUMERICHOST);
        dprintf("cvthname(%s)\n", ip);
 
        if (error) {
@@ -1371,8 +1460,7 @@ cvthname(struct sockaddr *f)
        sigprocmask(SIG_BLOCK, &nmask, &omask);
        error = getnameinfo((struct sockaddr *)f,
                            ((struct sockaddr *)f)->sa_len,
-                           hname, sizeof hname, NULL, 0,
-                           NI_NAMEREQD | withscopeid);
+                           hname, sizeof hname, NULL, 0, NI_NAMEREQD);
        sigprocmask(SIG_SETMASK, &omask, NULL);
        if (error) {
                dprintf("Host name for your address (%s) unknown\n", ip);
@@ -1427,9 +1515,9 @@ static void
 die(int signo)
 {
        struct filed *f;
+       struct funix *fx;
        int was_initialized;
        char buf[100];
-       int i;
 
        was_initialized = Initialized;
        Initialized = 0;        /* Don't log SIGCHLDs. */
@@ -1449,9 +1537,10 @@ die(int signo)
                errno = 0;
                logerror(buf);
        }
-       for (i = 0; i < nfunix; i++)
-               if (funixn[i] && funix[i] != -1)
-                       unlink(funixn[i]);
+       STAILQ_FOREACH(fx, &funixes, next)
+               unlink(fx->name);
+       pidfile_remove(pfh);
+
        exit(1);
 }
 
@@ -1579,7 +1668,7 @@ init(int signo)
                                p = LocalHostName;
                        for (i = 1; i < MAXHOSTNAMELEN - 1; i++) {
                                if (!isalnum(*p) && *p != '.' && *p != '-'
-                                    && *p != ',')
+                                   && *p != ',' && *p != ':' && *p != '%')
                                        break;
                                host[i] = *p++;
                        }
@@ -1594,13 +1683,24 @@ init(int signo)
                                continue;
                        }
                        for (i = 0; i < NAME_MAX; i++) {
-                               if (!isprint(p[i]))
+                               if (!isprint(p[i]) || isspace(p[i]))
                                        break;
                                prog[i] = p[i];
                        }
                        prog[i] = 0;
                        continue;
                }
+               for (p = cline + 1; *p != '\0'; p++) {
+                       if (*p != '#')
+                               continue;
+                       if (*(p - 1) == '\\') {
+                               strcpy(p - 1, p);
+                               p--;
+                               continue;
+                       }
+                       *p = '\0';
+                       break;
+               }
                for (i = strlen(cline) - 1; i >= 0 && isspace(cline[i]); i--)
                        cline[i] = '\0';
                f = (struct filed *)calloc(1, sizeof(*f));
@@ -1619,6 +1719,7 @@ init(int signo)
        Initialized = 1;
 
        if (Debug) {
+               int port;
                for (f = Files; f; f = f->f_next) {
                        for (i = 0; i <= LOG_NFACILITIES; i++)
                                if (f->f_pmask[i] == INTERNAL_NOPRI)
@@ -1637,7 +1738,14 @@ init(int signo)
                                break;
 
                        case F_FORW:
-                               printf("%s", f->f_un.f_forw.f_hname);
+                               port = (int)ntohs(((struct sockaddr_in *)
+                                   (f->f_un.f_forw.f_addr->ai_addr))->sin_port);
+                               if (port != 514) {
+                                       printf("%s:%d",
+                                               f->f_un.f_forw.f_hname, port);
+                               } else {
+                                       printf("%s", f->f_un.f_forw.f_hname);
+                               }
                                break;
 
                        case F_RING:
@@ -1782,7 +1890,7 @@ cfline(const char *line, struct filed *f, const char *prog, const char *host)
 
                /* decode priority name */
                if (*buf == '*') {
-                       pri = LOG_PRIMASK + 1;
+                       pri = LOG_PRIMASK;
                        pri_cmp = PRI_LT | PRI_EQ | PRI_GT;
                } else {
                        /* Ignore trailing spaces. */
@@ -1847,13 +1955,32 @@ cfline(const char *line, struct filed *f, const char *prog, const char *host)
 
        switch (*p) {
        case '@':
-               strlcpy(f->f_un.f_forw.f_hname, ++p,
-                       sizeof(f->f_un.f_forw.f_hname));
+               {
+                       char *tp;
+                       /*
+                        * scan forward to see if there is a port defined.
+                        * so we can't use strlcpy..
+                        */
+                       i = sizeof(f->f_un.f_forw.f_hname);
+                       tp = f->f_un.f_forw.f_hname;
+                       p++;
+
+                       while (*p && (*p != ':') && (i-- > 0)) {
+                               *tp++ = *p++;
+                       }
+                       *tp = '\0';
+               }
+               /* See if we copied a domain and have a port */
+               if (*p == ':')
+                       p++;
+               else
+                       p = NULL;
+
                memset(&hints, 0, sizeof(hints));
                hints.ai_family = family;
                hints.ai_socktype = SOCK_DGRAM;
-               error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints,
-                                   &res);
+               error = getaddrinfo(f->f_un.f_forw.f_hname,
+                               p ? p : "syslog", &hints, &res);
                if (error) {
                        logerror(gai_strerror(error));
                        break;
@@ -1863,7 +1990,7 @@ cfline(const char *line, struct filed *f, const char *prog, const char *host)
                break;
 
        case '/':
-               if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
+               if ((f->f_file = open(p, logflags, 0600)) < 0) {
                        f->f_type = F_UNUSED;
                        logerror(p);
                        break;
@@ -1921,7 +2048,8 @@ cfline(const char *line, struct filed *f, const char *prog, const char *host)
 
        case '|':
                f->f_un.f_pipe.f_pid = 0;
-               strlcpy(f->f_un.f_fname, p + 1, sizeof(f->f_un.f_fname));
+               strlcpy(f->f_un.f_pipe.f_pname, p + 1,
+                   sizeof(f->f_un.f_pipe.f_pname));
                f->f_type = F_PIPE;
                break;
 
@@ -2120,10 +2248,13 @@ allowaddr(char *s)
        char *cp1, *cp2;
        struct allowedpeer ap;
        struct servent *se;
-       int masklen = -1, i;
+       int masklen = -1;
        struct addrinfo hints, *res;
        struct in_addr *addrp, *maskp;
+#ifdef INET6
+       int i;
        u_int32_t *addr6p, *mask6p;
+#endif
        char ip[NI_MAXHOST];
 
 #ifdef INET6
@@ -2251,13 +2382,11 @@ allowaddr(char *s)
                        printf("numeric, ");
                        getnameinfo((struct sockaddr *)&ap.a_addr,
                                    ((struct sockaddr *)&ap.a_addr)->sa_len,
-                                   ip, sizeof ip, NULL, 0,
-                                   NI_NUMERICHOST | withscopeid);
+                                   ip, sizeof ip, NULL, 0, NI_NUMERICHOST);
                        printf("addr = %s, ", ip);
                        getnameinfo((struct sockaddr *)&ap.a_mask,
                                    ((struct sockaddr *)&ap.a_mask)->sa_len,
-                                   ip, sizeof ip, NULL, 0,
-                                   NI_NUMERICHOST | withscopeid);
+                                   ip, sizeof ip, NULL, 0, NI_NUMERICHOST);
                        printf("mask = %s; ", ip);
                } else {
                        printf("domainname = %s; ", ap.a_name);
@@ -2281,12 +2410,15 @@ allowaddr(char *s)
 static int
 validate(struct sockaddr *sa, const char *hname)
 {
-       int i, j, reject;
+       int i;
        size_t l1, l2;
        char *cp, name[NI_MAXHOST], ip[NI_MAXHOST], port[NI_MAXSERV];
        struct allowedpeer *ap;
        struct sockaddr_in *sin4, *a4p = NULL, *m4p = NULL;
+#ifdef INET6
+       int j, reject;
        struct sockaddr_in6 *sin6, *a6p = NULL, *m6p = NULL;
+#endif
        struct addrinfo hints, *res;
        u_short sport;
 
@@ -2306,7 +2438,7 @@ validate(struct sockaddr *sa, const char *hname)
                strlcat(name, LocalDomain, sizeof name);
        }
        if (getnameinfo(sa, sa->sa_len, ip, sizeof ip, port, sizeof port,
-                       NI_NUMERICHOST | withscopeid | NI_NUMERICSERV) != 0)
+                       NI_NUMERICHOST | NI_NUMERICSERV) != 0)
                return (0);     /* for safety, should not occur */
        dprintf("validate: dgram from IP %s, port %s, name %s;\n",
                ip, port, name);
@@ -2339,13 +2471,11 @@ validate(struct sockaddr *sa, const char *hname)
                                sin6 = (struct sockaddr_in6 *)sa;
                                a6p = (struct sockaddr_in6 *)&ap->a_addr;
                                m6p = (struct sockaddr_in6 *)&ap->a_mask;
-#ifdef NI_WITHSCOPEID
                                if (a6p->sin6_scope_id != 0 &&
                                    sin6->sin6_scope_id != a6p->sin6_scope_id) {
                                        dprintf("rejected in rule %d due to scope mismatch.\n", i);
                                        continue;
                                }
-#endif
                                reject = 0;
                                for (j = 0; j < 16; j += 4) {
                                        if ((*(u_int32_t *)&sin6->sin6_addr.s6_addr[j] & *(u_int32_t *)&m6p->sin6_addr.s6_addr[j])
@@ -2467,9 +2597,9 @@ p_open(const char *prog, pid_t *rpid)
        if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) {
                /* This is bad. */
                snprintf(errmsg, sizeof errmsg,
-                        "Warning: cannot change pipe to PID %d to "
-                        "non-blocking behaviour.",
-                        (int)pid);
+                              "Warning: cannot change pipe to PID %d to "
+                              "non-blocking behaviour.",
+                              (int)pid);
                logerror(errmsg);
        }
        *rpid = pid;
@@ -2538,8 +2668,8 @@ log_deadchild(pid_t pid, int status, const char *name)
                        return;
        }
        snprintf(buf, sizeof buf,
-                "Logging subprocess %d (%s) exited %s %d.",
-                pid, name, reason, code);
+                      "Logging subprocess %d (%s) exited %s %d.",
+                      pid, name, reason, code);
        logerror(buf);
 }
 
@@ -2571,15 +2701,13 @@ socksetup(int af, const char *bindhostname)
        *socks = 0;   /* num of sockets counter at start of array */
        s = socks + 1;
        for (r = res; r; r = r->ai_next) {
+               int on = 1;
                *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
                if (*s < 0) {
                        logerror("socket");
                        continue;
                }
-               if (r->ai_socktype != SOCK_STREAM)
-                       setsockbuffer(*s);
                if (r->ai_family == AF_INET6) {
-                       int on = 1;
                        if (setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY,
                                       (char *)&on, sizeof (on)) < 0) {
                                logerror("setsockopt");
@@ -2587,12 +2715,20 @@ socksetup(int af, const char *bindhostname)
                                continue;
                        }
                }
+               if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR,
+                              (char *)&on, sizeof (on)) < 0) {
+                       logerror("setsockopt");
+                       close(*s);
+                       continue;
+               }
                if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
                        close(*s);
                        logerror("bind");
                        continue;
                }
 
+               double_rbuf(*s);
+
                (*socks)++;
                s++;
        }
@@ -2610,21 +2746,8 @@ socksetup(int af, const char *bindhostname)
        return (socks);
 }
 
-/*
- * Most systems default to a fairly small amount of receive buffer space,
- * set a reasonable buffer size.
- */
-static
-void
-setsockbuffer(int fd)
-{
-       int bytes = 65536;
-
-       setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bytes, sizeof(bytes));
-}
-
 ssize_t
-rbwritev(struct filed *f, struct iovec *iov, int iovcnt) 
+rbwritev(struct filed *f, struct iovec *iov, int iovcnt)
 {
        int i;
        ssize_t out = 0;
@@ -2641,19 +2764,19 @@ rbwritev(struct filed *f, struct iovec *iov, int iovcnt)
 
 
 ssize_t
-rbwrite(struct filed *f, char *buf, size_t nbytes) 
+rbwrite(struct filed *f, char *buf, size_t nbytes)
 {
        size_t maxwrite;
        ssize_t error;
        ssize_t out;
 
-       maxwrite = f->f_un.f_ring.f_footer->cf_max - 
+       maxwrite = f->f_un.f_ring.f_footer->cf_max -
                   f->f_un.f_ring.f_footer->cf_next;
        out = 0;
 
        f->f_un.f_ring.f_footer->cf_lock = 1;
        while (nbytes > 0) {
-               maxwrite = f->f_un.f_ring.f_footer->cf_max - 
+               maxwrite = f->f_un.f_ring.f_footer->cf_max -
                           f->f_un.f_ring.f_footer->cf_next;
                if (maxwrite > nbytes)
                        maxwrite = nbytes;
@@ -2667,14 +2790,24 @@ rbwrite(struct filed *f, char *buf, size_t nbytes)
                out += error;
                buf += error;
                f->f_un.f_ring.f_footer->cf_next += error;
-               if (f->f_un.f_ring.f_footer->cf_next == 
+               if (f->f_un.f_ring.f_footer->cf_next ==
                    f->f_un.f_ring.f_footer->cf_max) {
                        f->f_un.f_ring.f_footer->cf_next = 0;
                        f->f_un.f_ring.f_footer->cf_wrap = 1;
                }
-               
        }
-                       
+
        f->f_un.f_ring.f_footer->cf_lock = 0;
        return (out);
 }
+
+static void
+double_rbuf(int fd)
+{
+       socklen_t slen, len;
+
+       if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, &slen) == 0) {
+               len *= 2;
+               setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, slen);
+       }
+}