Synchronize syslogd with FreeBSD. Primarily syslogd.c/1.129. This primarily
authorMatthew Dillon <dillon@dragonflybsd.org>
Mon, 9 Aug 2004 20:11:19 +0000 (20:11 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Mon, 9 Aug 2004 20:11:19 +0000 (20:11 +0000)
adds code to avoid fsync()ing the log file line-by-line when further input
from the pipe is pending.

The FreeBSD commit message for 1.129:
 date: 2004/07/04 19:13:58;  author: cperciva;  state: Exp;  lines: +25 -3
 Where syslogd would have fsync()ed a file in the past, instead set a flag
 FFLAG_NEEDSYNC and fsync the file when select() next returns zero.  This
 dramatically speeds up the process of logging large amounts of data, while
 leaving the essential semantics (that data can be expected to be on disk
 if we crash) unchanged.

 In my tests, this speeds up the rc phase of booting by 18-20%. [1]

Suggested-by: Barry Bouwsma
Source: FreeBSD

usr.sbin/syslogd/Makefile
usr.sbin/syslogd/syslog.conf.5
usr.sbin/syslogd/syslogd.8
usr.sbin/syslogd/syslogd.c

index 5ff4cb2..d76deb3 100644 (file)
@@ -1,6 +1,7 @@
 #      @(#)Makefile    8.1 (Berkeley) 6/6/93
-# $FreeBSD: src/usr.sbin/syslogd/Makefile,v 1.3.6.4 2003/05/19 16:23:03 gshapiro Exp $
-# $DragonFly: src/usr.sbin/syslogd/Makefile,v 1.2 2003/06/17 04:30:03 dillon Exp $
+# $FreeBSD: src/usr.sbin/syslogd/Makefile,v 1.12 2004/02/05 22:44:25 ru Exp $
+# $DragonFly: src/usr.sbin/syslogd/Makefile,v 1.3 2004/08/09 20:11:19 dillon Exp $
+#
 
 .PATH: ${.CURDIR}/../../usr.bin/wall
 
@@ -8,11 +9,10 @@ PROG= syslogd
 MAN=   syslog.conf.5 syslogd.8
 SRCS=  syslogd.c ttymsg.c
 
-CFLAGS+=-DINET6 -I${.CURDIR}/../../usr.bin/wall
-
-DPADD+=        ${LIBUTIL}
-LDADD+=        -lutil
+DPADD= ${LIBUTIL}
+LDADD= -lutil
 
 WARNS?=        1
+CFLAGS+=-DINET6 -I${.CURDIR}/../../usr.bin/wall
 
 .include <bsd.prog.mk>
index e425c80..4bba154 100644 (file)
@@ -30,8 +30,8 @@
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)syslog.conf.5      8.1 (Berkeley) 6/9/93
-.\" $FreeBSD: src/usr.sbin/syslogd/syslog.conf.5,v 1.16.2.11 2003/03/12 22:08:15 trhodes Exp $
-.\" $DragonFly: src/usr.sbin/syslogd/syslog.conf.5,v 1.2 2003/06/17 04:30:03 dillon Exp $
+.\" $FreeBSD: src/usr.sbin/syslogd/syslog.conf.5,v 1.35 2004/07/03 18:35:53 ru Exp $
+.\" $DragonFly: src/usr.sbin/syslogd/syslog.conf.5,v 1.3 2004/08/09 20:11:19 dillon Exp $
 .\"
 .Dd June 9, 1993
 .Dt SYSLOG.CONF 5
@@ -71,13 +71,13 @@ Note that if you use spaces as separators, your
 .Nm
 might be incompatible with other Unices or Unix-like systems.
 This functionality was added for ease of configuration
-(e.g. it is possible to cut-and-paste into
+(e.g.\& it is possible to cut-and-paste into
 .Nm ) ,
 and to avoid possible mistakes.
 This change however preserves
 backwards compatibility with the old style of
 .Nm
-(i.e. tab characters only).
+(i.e., tab characters only).
 .Pp
 The
 .Em selectors
@@ -197,6 +197,15 @@ or
 .Ql !-prog
 specification will match any message but the ones from that
 program.
+Multiple programs may be listed, separated by commas:
+.Ql !prog1,prog2
+matches messages from either program, while
+.Ql !-prog1,prog2
+matches all messages but those from
+.Ql prog1
+or
+.Ql prog2 .
+.Pp
 A
 .Em hostname
 specification of the form
@@ -216,6 +225,9 @@ from any host but the one specified.
 If the hostname is given as
 .Ql @ ,
 the local hostname will be used.
+As for program specifications, multiple comma-seprarated
+values may be specified for hostname specifications.
+.Pp
 A
 .Em program
 or
@@ -307,6 +319,22 @@ There are five forms:
 .It
 A pathname (beginning with a leading slash).
 Selected messages are appended to the file.
+.Pp
+To ensure that kernel messages are written to disk promptly,
+.Nm
+calls
+.Xr fsync 2
+after writing messages from the kernel.
+Other messages are not synced explicitly.
+You may prefix a pathname with the minus sign,
+.Dq - ,
+to forego syncing the specified file after every kernel message.
+Note that you might lose information if the system crashes
+immediately following a write attempt.
+Nevertheless, using the
+.Dq -
+option may improve performance,
+especially if the kernel is logging many messages.
 .It
 A hostname (preceded by an at
 .Pq Dq @
@@ -325,14 +353,17 @@ Selected messages are written to all logged-in users.
 A vertical bar
 .Pq Dq \&| ,
 followed by a command to pipe the selected
-messages to.  The command is passed to
+messages to.
+The command is passed to
 .Xr sh 1
 for evaluation, so usual shell metacharacters or input/output
-redirection can occur.  (Note however that redirecting
+redirection can occur.
+(Note however that redirecting
 .Xr stdio 3
 buffered output from the invoked command can cause additional delays,
 or even lost output data in case a logging subprocess exited with a
-signal.)  The command itself runs with
+signal.)
+The command itself runs with
 .Em stdout
 and
 .Em stderr
@@ -341,23 +372,28 @@ redirected to
 Upon receipt of a
 .Dv SIGHUP ,
 .Xr syslogd 8
-will close the pipe to the process.  If the process didn't exit
+will close the pipe to the process.
+If the process didn't exit
 voluntarily, it will be sent a
 .Dv SIGTERM
 signal after a grace period of up to 60 seconds.
 .Pp
 The command will only be started once data arrives that should be piped
-to it.  If it exited later, it will be restarted as necessary.  So if it
+to it.
+If it exited later, it will be restarted as necessary.
+So if it
 is desired that the subprocess should get exactly one line of input only
 (which can be very resource-consuming if there are a lot of messages
 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.
+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
 start the command with
 .Em exec
 so that the invoking shell process does not wait for the command to
-complete.  Warning: the process is started under the UID invoking
+complete.
+Warning: the process is started under the UID invoking
 .Xr syslogd 8 ,
 normally the superuser.
 .El
@@ -411,6 +447,10 @@ security.*                                         /var/log/security
 
 # Log all writes to /dev/console to a separate file.
 console.*                                              /var/log/console.log
+
+# Log ipfw messages without syncing after every message.
+!ipfw
+*.*                                                    -/var/log/ipfw
 .Ed
 .Sh IMPLEMENTATION NOTES
 The
@@ -446,9 +486,11 @@ or higher, not at the level of
 or higher.
 .Pp
 In networked environments, note that not all operating systems
-implement the same set of facilities.  The facilities
+implement the same set of facilities.
+The facilities
 authpriv, cron, ftp, and ntp that are known to this implementation
-might be absent on the target system.  Even worse, DEC UNIX uses
+might be absent on the target system.
+Even worse, DEC UNIX uses
 facility number 10 (which is authpriv in this implementation) to
 log events for their AdvFS file system.
 .Sh SEE ALSO
index 3f8e0ba..93d5bf3 100644 (file)
@@ -30,8 +30,8 @@
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)syslogd.8  8.1 (Berkeley) 6/6/93
-.\" $FreeBSD: src/usr.sbin/syslogd/syslogd.8,v 1.22.2.16 2003/03/12 22:08:15 trhodes Exp $
-.\" $DragonFly: src/usr.sbin/syslogd/syslogd.8,v 1.2 2003/06/17 04:30:03 dillon Exp $
+.\" $FreeBSD: src/usr.sbin/syslogd/syslogd.8,v 1.51 2004/07/02 23:12:57 ru Exp $
+.\" $DragonFly: src/usr.sbin/syslogd/syslogd.8,v 1.3 2004/08/09 20:11:19 dillon Exp $
 .\"
 .Dd November 24, 2001
 .Dt SYSLOGD 8
@@ -41,7 +41,7 @@
 .Nd log systems messages
 .Sh SYNOPSIS
 .Nm
-.Op Fl 46Acdknsuv
+.Op Fl 46Acdknosuv
 .Op Fl a Ar allowed_peer
 .Op Fl b Ar bind_address
 .Op Fl f Ar config_file
@@ -78,7 +78,8 @@ Allow
 .Ar allowed_peer
 to log to this
 .Nm
-using UDP datagrams.  Multiple
+using UDP datagrams.
+Multiple
 .Fl a
 options may be specified.
 .Pp
@@ -106,11 +107,13 @@ If specified,
 .Ar service
 is the name or number of an UDP service (see
 .Xr services 5 )
-the source packet must belong to.  A
+the source packet must belong to.
+A
 .Ar service
 of
 .Ql \&*
-allows packets being sent from any UDP port.  The default
+allows packets being sent from any UDP port.
+The default
 .Ar service
 is
 .Ql syslog .
@@ -121,7 +124,8 @@ is IPv4 address, a missing
 will be substituted by the historic class A or class B netmasks if
 .Ar ipaddr
 belongs into the address range of class A or B, respectively, or
-by 24 otherwise.  If
+by 24 otherwise.
+If
 .Ar ipaddr
 is IPv6 address, a missing
 .Ar masklen
@@ -133,7 +137,8 @@ will be substituted by 128.
 .Xc
 Accept datagrams where the reverse address lookup yields
 .Ar domainname
-for the sender address.  The meaning of
+for the sender address.
+The meaning of
 .Ar service
 is as explained above.
 .It Xo
@@ -166,7 +171,8 @@ If specified twice, disable this compression in all cases.
 .It Fl d
 Put
 .Nm
-into debugging mode.  This is probably only of use to developers working on
+into debugging mode.
+This is probably only of use to developers working on
 .Nm .
 .It Fl f
 Specify the pathname of an alternate configuration file;
@@ -188,6 +194,11 @@ Select the number of minutes between
 messages; the default is 20 minutes.
 .It Fl n
 Disable dns query for every request.
+.It Fl o
+Prefix kernel messages with the full kernel boot file as determined by
+.Xr getbootfile 3 .
+Without this, the kernel message prefix is always
+.Dq Li kernel: .
 .It Fl p
 Specify the pathname of an alternate log socket to be used instead;
 the default is
@@ -205,19 +216,24 @@ The primary use for this is to place additional log sockets in
 .Pa /var/run/log
 of various chroot filespaces.
 .It Fl s
-Operate in secure mode.  Do not log messages from remote machines.  If
+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 u
-Unique priority logging.  Only log messages at the specified priority.
+Unique priority logging.
+Only log messages at the specified priority.
 Without this option, messages at the stated priority or higher are logged.
 This option changes the default comparison from
 .Dq =>
 to
 .Dq = .
 .It Fl v
-Verbose logging.  If specified once, the numeric facility and priority are
-logged with each locally-written message.  If specified more than once,
+Verbose logging.
+If specified once, the numeric facility and priority are
+logged with each locally-written message.
+If specified more than once,
 the names of the facility and priority are logged with each locally-written
 message.
 .El
@@ -260,7 +276,7 @@ decimal number in angle braces, for example,
 .Sq Aq 5 .
 This priority code should map into the priorities defined in the
 include file
-.Aq Pa sys/syslog.h .
+.In sys/syslog.h .
 .Pp
 For security reasons,
 .Nm
@@ -303,9 +319,11 @@ extensions.
 .Sh BUGS
 The ability to log messages received in UDP packets is equivalent to
 an unauthenticated remote disk-filling service, and should probably be
-disabled by default.  Some sort of
+disabled by default.
+Some sort of
 .No inter- Ns Nm syslogd
-authentication mechanism ought to be worked out.  To prevent the worst
+authentication mechanism ought to be worked out.
+To prevent the worst
 abuse, use of the
 .Fl a
 option is therefore highly recommended.
@@ -313,7 +331,8 @@ option is therefore highly recommended.
 The
 .Fl a
 matching algorithm doesn't pretend to be very efficient; use of numeric
-IP addresses is faster than domain name comparison.  Since the allowed
+IP addresses is faster than domain name comparison.
+Since the allowed
 peer list is being walked linearly, peer groups where frequent messages
 are being anticipated from should be put early into the
 .Fl a
index ebfe12d..c5de032 100644 (file)
@@ -32,8 +32,8 @@
  *
  * @(#) 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.59.2.26 2003/05/20 17:13:53 gshapiro Exp $
- * $DragonFly: src/usr.sbin/syslogd/syslogd.c,v 1.2 2003/06/17 04:30:03 dillon Exp $
+ * $FreeBSD: src/usr.sbin/syslogd/syslogd.c,v 1.130 2004/07/04 19:52:48 cperciva Exp $
+ * $DragonFly: src/usr.sbin/syslogd/syslogd.c,v 1.3 2004/08/09 20:11:19 dillon Exp $
  */
 
 /*
@@ -49,7 +49,7 @@
  *
  * Defined Constants:
  *
- * MAXLINE -- the maximimum line length that can be handled.
+ * MAXLINE -- the maximum line length that can be handled.
  * DEFUPRI -- the default priority for user messages
  * DEFSPRI -- the default priority for kernel messages
  *
@@ -67,7 +67,7 @@
 #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 TTYMSGTIME     1               /* timeout passed to ttymsg */
 
 #include <sys/param.h>
 #include <sys/ioctl.h>
@@ -140,6 +140,8 @@ int funix[MAXFUNIX];
 /*
  * This structure represents the files that will have log
  * copies printed.
+ * We require f_file to be valid if f_type is F_FILE, F_CONSOLE, F_TTY
+ * or if f_type if F_PIPE and f_pid > 0.
  */
 
 struct filed {
@@ -174,6 +176,9 @@ struct filed {
        int     f_prevlen;                      /* length of f_prevline */
        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
 };
 
 /*
@@ -253,7 +258,7 @@ static struct filed consfile;       /* Console */
 static int     Debug;          /* debug flag */
 static int     resolve = 1;    /* resolve hostname */
 static char    LocalHostName[MAXHOSTNAMELEN];  /* our hostname */
-static char    *LocalDomain;   /* our local domain name */
+static const char *LocalDomain;        /* our local domain name */
 static int     *finet;         /* Internet datagram socket */
 static int     fklog = -1;     /* /dev/klog */
 static int     Initialized;    /* set when we have initialized ourselves */
@@ -266,6 +271,7 @@ static int  family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */
 static int     family = PF_INET; /* protocol family (IPv4 only) */
 #endif
 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 char    bootfile[MAXLINE+1]; /* booted kernel file */
@@ -277,6 +283,7 @@ 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? */
 
 volatile sig_atomic_t MarkSet, WantDie;
 
@@ -289,6 +296,7 @@ static int  deadq_remove(pid_t);
 static int     decode(const char *, CODE *);
 static void    die(int);
 static void    dodie(int);
+static void    dofsync(void);
 static void    domark(int);
 static void    fprintlog(struct filed *, int, const char *);
 static int     *socksetup(int, const char *);
@@ -297,6 +305,7 @@ 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    printsys(char *);
 static int     p_open(const char *, pid_t *);
@@ -326,7 +335,7 @@ main(int argc, char *argv[])
        socklen_t len;
 
        bindhostname = NULL;
-       while ((ch = getopt(argc, argv, "46Aa:b:cdf:kl:m:np:P:suv")) != -1)
+       while ((ch = getopt(argc, argv, "46Aa:b:cdf:kl:m:nop:P:suv")) != -1)
                switch (ch) {
                case '4':
                        family = PF_INET;
@@ -359,6 +368,8 @@ 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
@@ -371,7 +382,12 @@ main(int argc, char *argv[])
                case 'n':
                        resolve = 0;
                        break;
+               case 'o':
+                       use_bootfile = 1;
+                       break;
                case 'p':               /* path */
+                       if (strlen(optarg) >= sizeof(sunx.sun_path))
+                               errx(1, "%s path too long, exiting", optarg);
                        funixn[0] = optarg;
                        break;
                case 'P':               /* path for alt. PID */
@@ -386,7 +402,6 @@ main(int argc, char *argv[])
                case 'v':               /* log facility and priority */
                        LogFacPri++;
                        break;
-               case '?':
                default:
                        usage();
                }
@@ -535,9 +550,12 @@ main(int argc, char *argv[])
                                FD_SET(funix[i], fdsr);
                }
 
-               i = select(fdsrmax+1, fdsr, NULL, NULL, tvp);
+               i = select(fdsrmax+1, fdsr, NULL, NULL,
+                   needdofsync ? &tv : tvp);
                switch (i) {
                case 0:
+                       dofsync();
+                       needdofsync = 0;
                        if (tvp) {
                                tvp = NULL;
                                if (ppid != 1)
@@ -616,7 +634,7 @@ usage(void)
 {
 
        fprintf(stderr, "%s\n%s\n%s\n%s\n",
-               "usage: syslogd [-46Acdknsuv] [-a allowed_peer]",
+               "usage: syslogd [-46Acdknosuv] [-a allowed_peer]",
                "               [-b bind address] [-f config_file]",
                "               [-l log_socket] [-m mark_interval]",
                "               [-P pid_file] [-p log_socket]");
@@ -630,24 +648,31 @@ usage(void)
 static void
 printline(const char *hname, char *msg)
 {
+       char *p, *q;
+       long n;
        int c, pri;
-       char *p, *q, line[MAXLINE + 1];
+       char line[MAXLINE + 1];
 
        /* test for special codes */
-       pri = DEFUPRI;
        p = msg;
+       pri = DEFUPRI;
        if (*p == '<') {
-               pri = 0;
-               while (isdigit(*++p))
-                       pri = 10 * pri + (*p - '0');
-               if (*p == '>')
-                       ++p;
+               errno = 0;
+               n = strtol(p + 1, &q, 10);
+               if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) {
+                       p = q + 1;
+                       pri = n;
+               }
        }
        if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
                pri = DEFUPRI;
 
-       /* don't allow users to log kernel messages */
-       if (LOG_FAC(pri) == LOG_KERN && !KeepKernFac)
+       /*
+        * Don't allow users to log kernel messages.
+        * NOTE: since LOG_KERN == 0 this will also match
+        *       messages with no facility specified.
+        */
+       if ((pri & LOG_FACMASK) == LOG_KERN && !KeepKernFac)
                pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
 
        q = line;
@@ -719,24 +744,31 @@ readklog(void)
  * Take a raw input line from /dev/klog, format similar to syslog().
  */
 static void
-printsys(char *p)
+printsys(char *msg)
 {
-       int pri, flags;
+       char *p, *q;
+       long n;
+       int flags, isprintf, pri;
 
        flags = ISKERNEL | SYNC_FILE | ADDDATE; /* fsync after write */
+       p = msg;
        pri = DEFSPRI;
+       isprintf = 1;
        if (*p == '<') {
-               pri = 0;
-               while (isdigit(*++p))
-                       pri = 10 * pri + (*p - '0');
-               if (*p == '>')
-                       ++p;
-               if ((pri & LOG_FACMASK) == LOG_CONSOLE)
-                       flags |= IGN_CONS;
-       } else {
-               /* kernel printf's come out on console */
-               flags |= IGN_CONS;
+               errno = 0;
+               n = strtol(p + 1, &q, 10);
+               if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) {
+                       p = q + 1;
+                       pri = n;
+                       isprintf = 0;
+               }
        }
+       /*
+        * Kernel printf's and LOG_CONSOLE messages have been displayed
+        * on the console already.
+        */
+       if (isprintf || (pri & LOG_FACMASK) == LOG_CONSOLE)
+               flags |= IGN_CONS;
        if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
                pri = DEFSPRI;
        logmsg(pri, p, LocalHostName, flags);
@@ -744,6 +776,50 @@ printsys(char *p)
 
 static time_t  now;
 
+/*
+ * Match a program or host name against a specification.
+ * Return a non-0 value if the message must be ignored
+ * based on the specification.
+ */
+static int
+skip_message(const char *name, const char *spec, int checkcase) {
+       const char *s;
+       char prev, next;
+       int exclude = 0;
+       /* Behaviour on explicit match */
+
+       if (spec == NULL)
+               return 0;
+       switch (*spec) {
+       case '-':
+               exclude = 1;
+               /*FALLTHROUGH*/
+       case '+':
+               spec++;
+               break;
+       default:
+               break;
+       }
+       if (checkcase)
+               s = strstr (spec, name);
+       else
+               s = strcasestr (spec, name);
+
+       if (s != NULL) {
+               prev = (s == spec ? ',' : *(s - 1));
+               next = *(s + strlen (name));
+
+               if (prev == ',' && (next == '\0' || next == ','))
+                       /* Explicit match: skip iff the spec is an
+                          exclusive one. */
+                       return exclude;
+       }
+
+       /* No explicit match for this name: skip the message iff
+          the spec is an inclusive one. */
+       return !exclude;
+}
+
 /*
  * Log a message to the appropriate log files, users, etc. based on
  * the priority.
@@ -794,7 +870,8 @@ logmsg(int pri, const char *msg, const char *from, int flags)
 
        /* extract program name */
        for (i = 0; i < NAME_MAX; i++) {
-               if (!isprint(msg[i]) || msg[i] == ':' || msg[i] == '[')
+               if (!isprint(msg[i]) || msg[i] == ':' || msg[i] == '[' ||
+                   msg[i] == '/')
                        break;
                prog[i] = msg[i];
        }
@@ -802,7 +879,8 @@ logmsg(int pri, const char *msg, const char *from, int flags)
 
        /* add kernel prefix for kernel messages */
        if (flags & ISKERNEL) {
-               snprintf(buf, sizeof(buf), "%s: %s", bootfile, msg);
+               snprintf(buf, sizeof(buf), "%s: %s",
+                   use_bootfile ? bootfile : "kernel", msg);
                msg = buf;
                msglen = strlen(buf);
        }
@@ -831,34 +909,12 @@ logmsg(int pri, const char *msg, const char *from, int flags)
                        continue;
 
                /* skip messages with the incorrect hostname */
-               if (f->f_host)
-                       switch (f->f_host[0]) {
-                       case '+':
-                               if (strcasecmp(from, f->f_host + 1) != 0)
-                                       continue;
-                               break;
-                       case '-':
-                               if (strcasecmp(from, f->f_host + 1) == 0)
-                                       continue;
-                               break;
-                       }
+               if (skip_message(from, f->f_host, 0))
+                       continue;
 
                /* skip messages with the incorrect program name */
-               if (f->f_program)
-                       switch (f->f_program[0]) {
-                       case '+':
-                               if (strcmp(prog, f->f_program + 1) != 0)
-                                       continue;
-                               break;
-                       case '-':
-                               if (strcmp(prog, f->f_program + 1) == 0)
-                                       continue;
-                               break;
-                       default:
-                               if (strcmp(prog, f->f_program) != 0)
-                                       continue;
-                               break;
-                       }
+               if (skip_message(prog, f->f_program, 1))
+                       continue;
 
                /* skip message to console if it has already been printed */
                if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
@@ -915,6 +971,20 @@ logmsg(int pri, const char *msg, const char *from, int flags)
        (void)sigsetmask(omask);
 }
 
+static void
+dofsync(void)
+{
+       struct filed *f;
+
+       for (f = Files; f; f = f->f_next) {
+               if ((f->f_type == F_FILE) &&
+                   (f->f_flags & FFLAG_NEEDSYNC)) {
+                       f->f_flags &= ~FFLAG_NEEDSYNC;
+                       (void)fsync(f->f_file);
+               }
+       }
+}
+
 static void
 fprintlog(struct filed *f, int flags, const char *msg)
 {
@@ -923,6 +993,7 @@ fprintlog(struct filed *f, int flags, const char *msg)
        struct addrinfo *r;
        int i, l, lsent = 0;
        char line[MAXLINE + 1], repbuf[80], greetings[200], *wmsg = NULL;
+       char nul[] = "", space[] = " ", lf[] = "\n", crlf[] = "\r\n";
        const char *msgret;
 
        v = iov;
@@ -933,14 +1004,14 @@ fprintlog(struct filed *f, int flags, const char *msg)
                    f->f_prevhost, ctime(&now));
                if (v->iov_len > 0)
                        v++;
-               v->iov_base = "";
+               v->iov_base = nul;
                v->iov_len = 0;
                v++;
        } else {
                v->iov_base = f->f_lasttime;
                v->iov_len = 15;
                v++;
-               v->iov_base = " ";
+               v->iov_base = space;
                v->iov_len = 1;
                v++;
        }
@@ -982,7 +1053,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="";
+               v->iov_base = nul;
                v->iov_len = 0;
        }
        v++;
@@ -990,7 +1061,7 @@ fprintlog(struct filed *f, int flags, const char *msg)
        v->iov_base = f->f_prevhost;
        v->iov_len = strlen(v->iov_base);
        v++;
-       v->iov_base = " ";
+       v->iov_base = space;
        v->iov_len = 1;
        v++;
 
@@ -1026,11 +1097,12 @@ fprintlog(struct filed *f, int flags, const char *msg)
                if (strcasecmp(f->f_prevhost, LocalHostName))
                        l = snprintf(line, sizeof line - 1,
                            "<%d>%.15s Forwarded from %s: %s",
-                           f->f_prevpri, iov[0].iov_base, f->f_prevhost,
-                           iov[5].iov_base);
+                           f->f_prevpri, (char *)iov[0].iov_base,
+                           f->f_prevhost, (char *)iov[5].iov_base);
                else
                        l = snprintf(line, sizeof line - 1, "<%d>%.15s %s",
-                            f->f_prevpri, iov[0].iov_base, iov[5].iov_base);
+                            f->f_prevpri, (char *)iov[0].iov_base,
+                           (char *)iov[5].iov_base);
                if (l < 0)
                        l = 0;
                else if (l > MAXLINE)
@@ -1073,8 +1145,7 @@ fprintlog(struct filed *f, int flags, const char *msg)
                                /* case ENOBUFS: */
                                /* case ECONNREFUSED: */
                                default:
-                                       dprintf("removing entry\n", e);
-                                       (void)close(f->f_file);
+                                       dprintf("removing entry\n");
                                        f->f_type = F_UNUSED;
                                        break;
                                }
@@ -1084,7 +1155,7 @@ fprintlog(struct filed *f, int flags, const char *msg)
 
        case F_FILE:
                dprintf(" %s\n", f->f_un.f_fname);
-               v->iov_base = "\n";
+               v->iov_base = lf;
                v->iov_len = 1;
                if (writev(f->f_file, iov, 7) < 0) {
                        int e = errno;
@@ -1092,13 +1163,15 @@ fprintlog(struct filed *f, int flags, const char *msg)
                        f->f_type = F_UNUSED;
                        errno = e;
                        logerror(f->f_un.f_fname);
-               } else if (flags & SYNC_FILE)
-                       (void)fsync(f->f_file);
+               } else if ((flags & SYNC_FILE) && (f->f_flags & FFLAG_SYNC)) {
+                       f->f_flags |= FFLAG_NEEDSYNC;
+                       needdofsync = 1;
+               }
                break;
 
        case F_PIPE:
                dprintf(" %s\n", f->f_un.f_pipe.f_pname);
-               v->iov_base = "\n";
+               v->iov_base = lf;
                v->iov_len = 1;
                if (f->f_un.f_pipe.f_pid == 0) {
                        if ((f->f_file = p_open(f->f_un.f_pipe.f_pname,
@@ -1129,7 +1202,7 @@ fprintlog(struct filed *f, int flags, const char *msg)
 
        case F_TTY:
                dprintf(" %s%s\n", _PATH_DEV, f->f_un.f_fname);
-               v->iov_base = "\r\n";
+               v->iov_base = crlf;
                v->iov_len = 2;
 
                errno = 0;      /* ttymsg() only sometimes returns an errno */
@@ -1142,7 +1215,7 @@ fprintlog(struct filed *f, int flags, const char *msg)
        case F_USERS:
        case F_WALL:
                dprintf("\n");
-               v->iov_base = "\r\n";
+               v->iov_base = crlf;
                v->iov_len = 2;
                wallmsg(f, iov);
                break;
@@ -1179,7 +1252,9 @@ wallmsg(struct filed *f, struct iovec *iov)
        while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) {
                if (ut.ut_name[0] == '\0')
                        continue;
-               (void)strlcpy(line, ut.ut_line, sizeof(line));
+               /* We must use strncpy since ut_* may not be NUL terminated. */
+               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) {
                                errno = 0;      /* already in msg */
@@ -1300,7 +1375,12 @@ static void
 logerror(const char *type)
 {
        char buf[512];
+       static int recursed = 0;
 
+       /* If there's an error while trying to log an error, give up. */
+       if (recursed)
+               return;
+       recursed++;
        if (errno)
                (void)snprintf(buf,
                    sizeof buf, "syslogd: %s: %s", type, strerror(errno));
@@ -1309,6 +1389,7 @@ logerror(const char *type)
        errno = 0;
        dprintf("%s\n", buf);
        logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
+       recursed--;
 }
 
 static void
@@ -1325,8 +1406,10 @@ die(int signo)
                /* flush any pending output */
                if (f->f_prevcount)
                        fprintlog(f, 0, (char *)NULL);
-               if (f->f_type == F_PIPE)
+               if (f->f_type == F_PIPE && f->f_un.f_pipe.f_pid > 0) {
                        (void)close(f->f_file);
+                       f->f_un.f_pipe.f_pid = 0;
+               }
        }
        Initialized = was_initialized;
        if (signo) {
@@ -1356,6 +1439,7 @@ init(int signo)
        char host[MAXHOSTNAMELEN];
        char oldLocalHostName[MAXHOSTNAMELEN];
        char hostMsg[2*MAXHOSTNAMELEN+40];
+       char bootfileMsg[LINE_MAX];
 
        dprintf("init\n");
 
@@ -1391,10 +1475,11 @@ init(int signo)
                        (void)close(f->f_file);
                        break;
                case F_PIPE:
-                       (void)close(f->f_file);
-                       if (f->f_un.f_pipe.f_pid > 0)
+                       if (f->f_un.f_pipe.f_pid > 0) {
+                               (void)close(f->f_file);
                                deadq_enter(f->f_un.f_pipe.f_pid,
                                            f->f_un.f_pipe.f_pname);
+                       }
                        f->f_un.f_pipe.f_pid = 0;
                        break;
                }
@@ -1457,7 +1542,8 @@ init(int signo)
                        if (*p == '@')
                                p = LocalHostName;
                        for (i = 1; i < MAXHOSTNAMELEN - 1; i++) {
-                               if (!isalnum(*p) && *p != '.' && *p != '-')
+                               if (!isalnum(*p) && *p != '.' && *p != '-'
+                                    && *p != ',')
                                        break;
                                host[i] = *p++;
                        }
@@ -1479,9 +1565,8 @@ init(int signo)
                        prog[i] = 0;
                        continue;
                }
-               for (p = strchr(cline, '\0'); isspace(*--p);)
-                       continue;
-               *++p = '\0';
+               for (i = strlen(cline) - 1; i >= 0 && isspace(cline[i]); i--)
+                       cline[i] = '\0';
                f = (struct filed *)calloc(1, sizeof(*f));
                if (f == NULL) {
                        logerror("calloc");
@@ -1546,6 +1631,16 @@ init(int signo)
                logmsg(LOG_SYSLOG|LOG_INFO, hostMsg, LocalHostName, ADDDATE);
                dprintf("%s\n", hostMsg);
        }
+       /*
+        * Log the kernel boot file if we aren't going to use it as
+        * the prefix, and if this is *not* a restart.
+        */
+       if (signo == 0 && !use_bootfile) {
+               (void)snprintf(bootfileMsg, sizeof(bootfileMsg),
+                   "syslogd: kernel boot file is %s", bootfile);
+               logmsg(LOG_KERN|LOG_INFO, bootfileMsg, LocalHostName, ADDDATE);
+               dprintf("%s\n", bootfileMsg);
+       }
 }
 
 /*
@@ -1555,7 +1650,7 @@ static void
 cfline(const char *line, struct filed *f, const char *prog, const char *host)
 {
        struct addrinfo hints, *res;
-       int error, i, pri;
+       int error, i, pri, syncfile;
        const char *p, *q;
        char *bp;
        char buf[MAXLINE], ebuf[100];
@@ -1649,6 +1744,10 @@ cfline(const char *line, struct filed *f, const char *prog, const char *host)
                        pri = LOG_PRIMASK + 1;
                        pri_cmp = PRI_LT | PRI_EQ | PRI_GT;
                } else {
+                       /* Ignore trailing spaces. */
+                       for (i = strlen(buf) - 1; i >= 0 && buf[i] == ' '; i--)
+                               buf[i] = '\0';
+
                        pri = decode(buf, prioritynames);
                        if (pri < 0) {
                                (void)snprintf(ebuf, sizeof ebuf,
@@ -1699,6 +1798,12 @@ cfline(const char *line, struct filed *f, const char *prog, const char *host)
        while (*p == '\t' || *p == ' ')
                p++;
 
+       if (*p == '-') {
+               syncfile = 0;
+               p++;
+       } else
+               syncfile = 1;
+
        switch (*p) {
        case '@':
                (void)strlcpy(f->f_un.f_forw.f_hname, ++p,
@@ -1722,6 +1827,8 @@ cfline(const char *line, struct filed *f, const char *prog, const char *host)
                        logerror(p);
                        break;
                }
+               if (syncfile)
+                       f->f_flags |= FFLAG_SYNC;
                if (isatty(f->f_file)) {
                        if (strcmp(p, ctty) == 0)
                                f->f_type = F_CONSOLE;
@@ -2209,9 +2316,10 @@ validate(struct sockaddr *sa, const char *hname)
  * opposed to a FILE *.
  */
 static int
-p_open(const char *prog, pid_t *pid)
+p_open(const char *prog, pid_t *rpid)
 {
        int pfd[2], nulldesc, i;
+       pid_t pid;
        sigset_t omask, mask;
        char *argv[4]; /* sh -c cmd NULL */
        char errmsg[200];
@@ -2226,7 +2334,7 @@ p_open(const char *prog, pid_t *pid)
        sigaddset(&mask, SIGALRM);
        sigaddset(&mask, SIGHUP);
        sigprocmask(SIG_BLOCK, &mask, &omask);
-       switch ((*pid = fork())) {
+       switch ((pid = fork())) {
        case -1:
                sigprocmask(SIG_SETMASK, &omask, 0);
                close(nulldesc);
@@ -2284,9 +2392,10 @@ p_open(const char *prog, pid_t *pid)
                (void)snprintf(errmsg, sizeof errmsg,
                               "Warning: cannot change pipe to PID %d to "
                               "non-blocking behaviour.",
-                              (int)*pid);
+                              (int)pid);
                logerror(errmsg);
        }
+       *rpid = pid;
        return (pfd[1]);
 }