svn commit: r332099 - head/usr.sbin/syslogd

Ed Schouten ed at FreeBSD.org
Fri Apr 6 12:57:02 UTC 2018


Author: ed
Date: Fri Apr  6 12:57:01 2018
New Revision: 332099
URL: https://svnweb.freebsd.org/changeset/base/332099

Log:
  Add RFC 5424 syslog message parsing to syslogd.
  
  Syslogd currently uses the RFC 3164 format for its log messages.One
  limitation of RFC 3164 is that it cannot be used to log entries with
  sub-second precision timestamps. One of our users has expressed a desire
  for doing this for doing some basic performance measurements.
  
  This change attempts to make a first cut at switching to RFC 5424 based
  logging. The first step is to alter syslogd's input path to properly
  parse such messages. It alters the logmsg() prototype to match the
  fields of RFC 5424. The parsemsg() function is extended to parse both
  RFC 3164 and 5424 messages and call into logmsg() accordingly.
  
  Additional changes include:
  
  - Introducing proper parsing of timestamps, so that they can be printed
    in any desired output format. This means we need to infer the year and
    timezone for RFC 3164 timestamps.
  - Removing ISKERNEL. This can now be realised by simply providing an
    APP-NAME (== "kernel").
  - Extending RFC 3164 parsing to trim off the TAG prefix and using that
    to derive APP-NAME and PROCID.
  - Increase MAXLINE. RFC 5424 mentions we should support 2k messages.
  
  Differential Revision:	https://reviews.freebsd.org/D14926

Modified:
  head/usr.sbin/syslogd/syslogd.c

Modified: head/usr.sbin/syslogd/syslogd.c
==============================================================================
--- head/usr.sbin/syslogd/syslogd.c	Fri Apr  6 12:39:47 2018	(r332098)
+++ head/usr.sbin/syslogd/syslogd.c	Fri Apr  6 12:57:01 2018	(r332099)
@@ -28,6 +28,33 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 Prodrive Technologies, https://prodrive-technologies.com/
+ * Author: Ed Schouten <ed at FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
 
 #ifndef lint
 static const char copyright[] =
@@ -71,8 +98,7 @@ __FBSDID("$FreeBSD$");
  */
 
 /* Maximum number of characters in time of last occurrence */
-#define	MAXDATELEN	16
-#define	MAXLINE		1024		/* maximum line length */
+#define	MAXLINE		2048		/* maximum line length */
 #define	MAXSVLINE	MAXLINE		/* maximum saved line length */
 #define	DEFUPRI		(LOG_USER|LOG_NOTICE)
 #define	DEFSPRI		(LOG_KERN|LOG_CRIT)
@@ -97,8 +123,8 @@ __FBSDID("$FreeBSD$");
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #endif
-#include <netdb.h>
 
+#include <assert.h>
 #include <ctype.h>
 #include <dirent.h>
 #include <err.h>
@@ -107,6 +133,7 @@ __FBSDID("$FreeBSD$");
 #include <fnmatch.h>
 #include <libutil.h>
 #include <limits.h>
+#include <netdb.h>
 #include <paths.h>
 #include <signal.h>
 #include <stdio.h>
@@ -174,8 +201,17 @@ static STAILQ_HEAD(, socklist) shead = STAILQ_HEAD_INI
 #define	IGN_CONS	0x001	/* don't print on console */
 #define	SYNC_FILE	0x002	/* do fsync on file after printing */
 #define	MARK		0x008	/* this message is a mark */
-#define	ISKERNEL	0x010	/* kernel generated message */
 
+/* Timestamps of log entries. */
+struct logtime {
+	struct tm	tm;
+	suseconds_t	usec;
+};
+
+/* Traditional syslog timestamp format. */
+#define	RFC3164_DATELEN	15
+#define	RFC3164_DATEFMT	"%b %e %H:%M:%S"
+
 /*
  * This structure represents the files that will have log
  * copies printed.
@@ -215,10 +251,10 @@ struct filed {
 #define	fu_pipe_pname	f_un.f_pipe.f_pname
 #define	fu_pipe_pid	f_un.f_pipe.f_pid
 	char	f_prevline[MAXSVLINE];		/* last message logged */
-	char	f_lasttime[MAXDATELEN];		/* time of last occurrence */
+	struct logtime f_lasttime;		/* time of last occurrence */
 	char	f_prevhost[MAXHOSTNAMELEN];	/* host from which recd. */
 	int	f_prevpri;			/* pri of f_prevline */
-	int	f_prevlen;			/* length of f_prevline */
+	size_t	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 */
@@ -352,7 +388,8 @@ static void	domark(int);
 static void	fprintlog(struct filed *, int, const char *);
 static void	init(int);
 static void	logerror(const char *);
-static void	logmsg(int, const char *, const char *, const char *, int);
+static void	logmsg(int, const struct logtime *, const char *, const char *,
+    const char *, const char *, const char *, const char *, int);
 static void	log_deadchild(pid_t, int, const char *);
 static void	markit(void);
 static int	socksetup(struct peer *);
@@ -852,17 +889,352 @@ usage(void)
 }
 
 /*
- * Take a raw input line, extract PRI, TIMESTAMP and HOSTNAME from the message,
- * and print the message on the appropriate log files.
+ * Removes characters from log messages that are unsafe to display.
+ * TODO: Permit UTF-8 strings that include a BOM per RFC 5424?
  */
 static void
+parsemsg_remove_unsafe_characters(const char *in, char *out, size_t outlen)
+{
+	char *q;
+	int c;
+
+	q = out;
+	while ((c = (unsigned char)*in++) != '\0' && q < out + outlen - 4) {
+		if (mask_C1 && (c & 0x80) && c < 0xA0) {
+			c &= 0x7F;
+			*q++ = 'M';
+			*q++ = '-';
+		}
+		if (isascii(c) && iscntrl(c)) {
+			if (c == '\n') {
+				*q++ = ' ';
+			} else if (c == '\t') {
+				*q++ = '\t';
+			} else {
+				*q++ = '^';
+				*q++ = c ^ 0100;
+			}
+		} else {
+			*q++ = c;
+		}
+	}
+	*q = '\0';
+}
+
+/*
+ * Parses a syslog message according to RFC 5424, assuming that PRI and
+ * VERSION (i.e., "<%d>1 ") have already been parsed by parsemsg(). The
+ * parsed result is passed to logmsg().
+ */
+static void
+parsemsg_rfc5424(const char *from, int pri, char *msg)
+{
+	const struct logtime *timestamp;
+	struct logtime timestamp_remote = { 0 };
+	const char *omsg, *hostname, *app_name, *procid, *msgid,
+	    *structured_data;
+	char line[MAXLINE + 1];
+
+#define	FAIL_IF(field, expr) do {					\
+	if (expr) {							\
+		dprintf("Failed to parse " field " from %s: %s\n",	\
+		    from, omsg);					\
+		return;							\
+	}								\
+} while (0)
+#define	PARSE_CHAR(field, sep) do {					\
+	FAIL_IF(field, *msg != sep);					\
+	++msg;								\
+} while (0)
+#define	IF_NOT_NILVALUE(var)						\
+	if (msg[0] == '-' && msg[1] == ' ') {				\
+		msg += 2;						\
+		var = NULL;						\
+	} else if (msg[0] == '-' && msg[1] == '\0') {			\
+		++msg;							\
+		var = NULL;						\
+	} else
+
+	omsg = msg;
+	IF_NOT_NILVALUE(timestamp) {
+		/* Parse RFC 3339-like timestamp. */
+#define	PARSE_NUMBER(dest, length, min, max) do {			\
+	int i, v;							\
+									\
+	v = 0;								\
+	for (i = 0; i < length; ++i) {					\
+		FAIL_IF("TIMESTAMP", *msg < '0' || *msg > '9');		\
+		v = v * 10 + *msg++ - '0';				\
+	}								\
+	FAIL_IF("TIMESTAMP", v < min || v > max);			\
+	dest = v;							\
+} while (0)
+		/* Date and time. */
+		PARSE_NUMBER(timestamp_remote.tm.tm_year, 4, 0, 9999);
+		timestamp_remote.tm.tm_year -= 1900;
+		PARSE_CHAR("TIMESTAMP", '-');
+		PARSE_NUMBER(timestamp_remote.tm.tm_mon, 2, 1, 12);
+		--timestamp_remote.tm.tm_mon;
+		PARSE_CHAR("TIMESTAMP", '-');
+		PARSE_NUMBER(timestamp_remote.tm.tm_mday, 2, 1, 31);
+		PARSE_CHAR("TIMESTAMP", 'T');
+		PARSE_NUMBER(timestamp_remote.tm.tm_hour, 2, 0, 23);
+		PARSE_CHAR("TIMESTAMP", ':');
+		PARSE_NUMBER(timestamp_remote.tm.tm_min, 2, 0, 59);
+		PARSE_CHAR("TIMESTAMP", ':');
+		PARSE_NUMBER(timestamp_remote.tm.tm_sec, 2, 0, 59);
+		/* Perform normalization. */
+		timegm(&timestamp_remote.tm);
+		/* Optional: fractional seconds. */
+		if (msg[0] == '.' && msg[1] >= '0' && msg[1] <= '9') {
+			int i;
+
+			++msg;
+			for (i = 100000; i != 0; i /= 10) {
+				if (*msg < '0' || *msg > '9')
+					break;
+				timestamp_remote.usec += (*msg++ - '0') * i;
+			}
+		}
+		/* Timezone. */
+		if (*msg == 'Z') {
+			/* UTC. */
+			++msg;
+		} else {
+			int sign, tz_hour, tz_min;
+
+			/* Local time zone offset. */
+			FAIL_IF("TIMESTAMP", *msg != '-' && *msg != '+');
+			sign = *msg++ == '-' ? -1 : 1;
+			PARSE_NUMBER(tz_hour, 2, 0, 23);
+			PARSE_CHAR("TIMESTAMP", ':');
+			PARSE_NUMBER(tz_min, 2, 0, 59);
+			timestamp_remote.tm.tm_gmtoff =
+			    sign * (tz_hour * 3600 + tz_min * 60);
+		}
+#undef PARSE_NUMBER
+		PARSE_CHAR("TIMESTAMP", ' ');
+		timestamp = RemoteAddDate ? NULL : &timestamp_remote;
+	}
+
+	/* String fields part of the HEADER. */
+#define	PARSE_STRING(field, var)					\
+	IF_NOT_NILVALUE(var) {						\
+		var = msg;						\
+		while (*msg >= '!' && *msg <= '~')			\
+			++msg;						\
+		FAIL_IF(field, var == msg);				\
+		PARSE_CHAR(field, ' ');					\
+		msg[-1] = '\0';						\
+	}
+	PARSE_STRING("HOSTNAME", hostname);
+	PARSE_STRING("APP-NAME", app_name);
+	PARSE_STRING("PROCID", procid);
+	PARSE_STRING("MSGID", msgid);
+#undef PARSE_STRING
+
+	/* Structured data. */
+#define	PARSE_SD_NAME() do {						\
+	const char *start;						\
+									\
+	start = msg;							\
+	while (*msg >= '!' && *msg <= '~' && *msg != '=' &&		\
+	    *msg != ']' && *msg != '"')					\
+		++msg;							\
+	FAIL_IF("STRUCTURED-NAME", start == msg);			\
+} while (0)
+	IF_NOT_NILVALUE(structured_data) {
+		/* SD-ELEMENT. */
+		while (*msg == '[') {
+			++msg;
+			/* SD-ID. */
+			PARSE_SD_NAME();
+			/* SD-PARAM. */
+			while (*msg == ' ') {
+				++msg;
+				/* PARAM-NAME. */
+				PARSE_SD_NAME();
+				PARSE_CHAR("STRUCTURED-NAME", '=');
+				PARSE_CHAR("STRUCTURED-NAME", '"');
+				while (*msg != '"') {
+					FAIL_IF("STRUCTURED-NAME",
+					    *msg == '\0');
+					if (*msg++ == '\\') {
+						FAIL_IF("STRUCTURED-NAME",
+						    *msg == '\0');
+						++msg;
+					}
+				}
+				++msg;
+			}
+			PARSE_CHAR("STRUCTURED-NAME", ']');
+		}
+		PARSE_CHAR("STRUCTURED-NAME", ' ');
+		msg[-1] = '\0';
+	}
+#undef PARSE_SD_NAME
+
+#undef FAIL_IF
+#undef PARSE_CHAR
+#undef IF_NOT_NILVALUE
+
+	parsemsg_remove_unsafe_characters(msg, line, sizeof(line));
+	logmsg(pri, timestamp, from, app_name, procid, msgid,
+	    structured_data, line, 0);
+}
+
+/*
+ * Trims the application name ("TAG" in RFC 3164 terminology) and
+ * process ID from a message if present.
+ */
+static void
+parsemsg_rfc3164_app_name_procid(char **msg, const char **app_name,
+    const char **procid) {
+	char *m, *app_name_begin, *procid_begin;
+	size_t app_name_length, procid_length;
+
+	m = *msg;
+
+	/* Application name. */
+	app_name_begin = m;
+	app_name_length = strspn(m,
+	    "abcdefghijklmnopqrstuvwxyz"
+	    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+	    "0123456789"
+	    "_-");
+	if (app_name_length == 0)
+		goto bad;
+	m += app_name_length;
+
+	/* Process identifier (optional). */
+	if (*m == '[') {
+		procid_begin = ++m;
+		procid_length = strspn(m, "0123456789");
+		if (procid_length == 0)
+			goto bad;
+		m += procid_length;
+		if (*m++ != ']')
+			goto bad;
+	} else {
+		procid_begin = NULL;
+		procid_length = 0;
+	}
+
+	/* Separator. */
+	if (m[0] != ':' || m[1] != ' ')
+		goto bad;
+
+	/* Split strings from input. */
+	app_name_begin[app_name_length] = '\0';
+	if (procid_begin != 0)
+		procid_begin[procid_length] = '\0';
+
+	*msg = m + 2;
+	*app_name = app_name_begin;
+	*procid = procid_begin;
+	return;
+bad:
+	*app_name = NULL;
+	*procid = NULL;
+}
+
+/*
+ * Parses a syslog message according to RFC 3164, assuming that PRI
+ * (i.e., "<%d>") has already been parsed by parsemsg(). The parsed
+ * result is passed to logmsg().
+ */
+static void
+parsemsg_rfc3164(const char *from, int pri, char *msg)
+{
+	struct tm tm_parsed;
+	const struct logtime *timestamp;
+	struct logtime timestamp_remote = { 0 };
+	const char *app_name, *procid;
+	size_t i, msglen;
+	char line[MAXLINE + 1];
+
+	/* Parse the timestamp provided by the remote side. */
+	if (strptime(msg, RFC3164_DATEFMT, &tm_parsed) !=
+	    msg + RFC3164_DATELEN || msg[RFC3164_DATELEN] != ' ') {
+		dprintf("Failed to parse TIMESTAMP from %s: %s\n", from, msg);
+		return;
+	}
+	msg += RFC3164_DATELEN + 1;
+
+	if (!RemoteAddDate) {
+		struct tm tm_now;
+		time_t t_now;
+		int year;
+
+		/*
+		 * As the timestamp does not contain the year number,
+		 * daylight saving time information, nor a time zone,
+		 * attempt to infer it. Due to clock skews, the
+		 * timestamp may even be part of the next year. Use the
+		 * last year for which the timestamp is at most one week
+		 * in the future.
+		 *
+		 * This loop can only run for at most three iterations
+		 * before terminating.
+		 */
+		t_now = time(NULL);
+		localtime_r(&t_now, &tm_now);
+		for (year = tm_now.tm_year + 1;; --year) {
+			assert(year >= tm_now.tm_year - 1);
+			timestamp_remote.tm = tm_parsed;
+			timestamp_remote.tm.tm_year = year;
+			timestamp_remote.tm.tm_isdst = -1;
+			if (mktime(&timestamp_remote.tm) <
+			    t_now + 7 * 24 * 60 * 60)
+				break;
+		}
+		timestamp = &timestamp_remote;
+	} else
+		timestamp = NULL;
+
+	/*
+	 * A single space character MUST also follow the HOSTNAME field.
+	 */
+	msglen = strlen(msg);
+	for (i = 0; i < MIN(MAXHOSTNAMELEN, msglen); i++) {
+		if (msg[i] == ' ') {
+			if (RemoteHostname) {
+				msg[i] = '\0';
+				from = msg;
+			}
+			msg += i + 1;
+			break;
+		}
+		/*
+		 * Support non RFC compliant messages, without hostname.
+		 */
+		if (msg[i] == ':')
+			break;
+	}
+	if (i == MIN(MAXHOSTNAMELEN, msglen)) {
+		dprintf("Invalid HOSTNAME from %s: %s\n", from, msg);
+		return;
+	}
+
+	/* Remove the TAG, if present. */
+	parsemsg_rfc3164_app_name_procid(&msg, &app_name, &procid);
+	parsemsg_remove_unsafe_characters(msg, line, sizeof(line));
+	logmsg(pri, timestamp, from, app_name, procid, NULL, NULL, line, 0);
+}
+
+/*
+ * Takes a raw input line, extracts PRI and determines whether the
+ * message is formatted according to RFC 3164 or RFC 5424. Continues
+ * parsing of addition fields in the message according to those
+ * standards and prints the message on the appropriate log files.
+ */
+static void
 parsemsg(const char *from, char *msg)
 {
-	const char *timestamp;
 	char *q;
 	long n;
-	int i, c, pri, msglen;
-	char line[MAXLINE + 1];
+	size_t i;
+	int pri;
 
 	/* Parse PRI. */
 	if (msg[0] != '<' || !isdigit(msg[1])) {
@@ -900,75 +1272,12 @@ parsemsg(const char *from, char *msg)
 	if ((pri & LOG_FACMASK) == LOG_KERN && !KeepKernFac)
 		pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
 
-	/*
-	 * The TIMESTAMP field is the local time and is in the format of
-	 * "Mmm dd hh:mm:ss" (without the quote marks).
-   	 * A single space character MUST follow the TIMESTAMP field.
-	 *
-	 * XXXGL: the check can be improved.
-	 */
+	/* Parse VERSION. */
 	msg += i + 1;
-	msglen = strlen(msg);
-	if (msglen < MAXDATELEN || msg[3] != ' ' || msg[6] != ' ' ||
-	    msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') {
-		dprintf("Invalid TIMESTAMP from %s: %s\n", from, msg);
-		return;
-	}
-
-	if (!RemoteAddDate)
-		timestamp = msg;
+	if (msg[0] == '1' && msg[1] == ' ')
+		parsemsg_rfc5424(from, pri, msg + 2);
 	else
-		timestamp = NULL;
-	msg += MAXDATELEN;
-	msglen -= MAXDATELEN;
-
-	/*
-	 * A single space character MUST also follow the HOSTNAME field.
-	 */
-	for (i = 0; i < MIN(MAXHOSTNAMELEN, msglen); i++) {
-		if (msg[i] == ' ') {
-			if (RemoteHostname) {
-				msg[i] = '\0';
-				from = msg;
-			}
-			msg += i + 1;
-			break;
-		}
-		/*
-		 * Support non RFC compliant messages, without hostname.
-		 */
-		if (msg[i] == ':')
-			break;
-	}
-	if (i == MIN(MAXHOSTNAMELEN, msglen)) {
-		dprintf("Invalid HOSTNAME from %s: %s\n", from, msg);
-		return;
-	}
-
-	q = line;
-	while ((c = (unsigned char)*msg++) != '\0' &&
-	    q < &line[sizeof(line) - 4]) {
-		if (mask_C1 && (c & 0x80) && c < 0xA0) {
-			c &= 0x7F;
-			*q++ = 'M';
-			*q++ = '-';
-		}
-		if (isascii(c) && iscntrl(c)) {
-			if (c == '\n') {
-				*q++ = ' ';
-			} else if (c == '\t') {
-				*q++ = '\t';
-			} else {
-				*q++ = '^';
-				*q++ = c ^ 0100;
-			}
-		} else {
-			*q++ = c;
-		}
-	}
-	*q = '\0';
-
-	logmsg(pri, timestamp, line, from, 0);
+		parsemsg_rfc3164(from, pri, msg);
 }
 
 /*
@@ -1022,7 +1331,7 @@ printsys(char *msg)
 	long n;
 	int flags, isprintf, pri;
 
-	flags = ISKERNEL | SYNC_FILE;	/* fsync after write */
+	flags = SYNC_FILE;	/* fsync after write */
 	p = msg;
 	pri = DEFSPRI;
 	isprintf = 1;
@@ -1043,7 +1352,7 @@ printsys(char *msg)
 		flags |= IGN_CONS;
 	if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
 		pri = DEFSPRI;
-	logmsg(pri, NULL, p, LocalHostName, flags);
+	logmsg(pri, NULL, LocalHostName, "kernel", NULL, NULL, NULL, p, flags);
 }
 
 static time_t	now;
@@ -1094,24 +1403,33 @@ skip_message(const char *name, const char *spec, int c
 }
 
 /*
- * Log a message to the appropriate log files, users, etc. based on
- * the priority.
+ * Logs a message to the appropriate log files, users, etc. based on the
+ * priority. Log messages are always formatted according to RFC 3164,
+ * even if they were in RFC 5424 format originally, The MSGID and
+ * STRUCTURED-DATA fields are thus discarded for the time being.
  */
 static void
-logmsg(int pri, const char *timestamp, const char *msg, const char *from,
-    int flags)
+logmsg(int pri, const struct logtime *timestamp, const char *from,
+    const char *app_name, const char *procid, const char *msgid __unused,
+    const char *structured_data __unused, const char *msg, int flags)
 {
+	struct timeval tv;
+	struct logtime timestamp_now;
 	struct filed *f;
-	int i, fac, msglen, prilev;
- 	char prog[NAME_MAX+1];
+	size_t msglen;
+	int fac, prilev;
 	char buf[MAXLINE+1];
 
 	dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
 	    pri, flags, from, msg);
 
-	(void)time(&now);
-	if (timestamp == NULL)
-		timestamp = ctime(&now) + 4;
+	(void)gettimeofday(&tv, NULL);
+	now = tv.tv_sec;
+	if (timestamp == NULL) {
+		localtime_r(&now, &timestamp_now.tm);
+		timestamp_now.usec = tv.tv_usec;
+		timestamp = &timestamp_now;
+	}
 
 	/* extract facility and priority level */
 	if (flags & MARK)
@@ -1125,22 +1443,17 @@ logmsg(int pri, const char *timestamp, const char *msg
 
 	prilev = LOG_PRI(pri);
 
-	/* Extract TAG part of the message (usually program name). */
-	for (i = 0; i < NAME_MAX; i++) {
-		if (!isprint(msg[i]) || msg[i] == ':' || msg[i] == '[' ||
-		    msg[i] == '/' || isspace(msg[i]))
-			break;
-		prog[i] = msg[i];
-	}
-	prog[i] = 0;
-
-	/* add kernel prefix for kernel messages */
-	if (flags & ISKERNEL) {
-		snprintf(buf, sizeof(buf), "%s: %s",
-		    use_bootfile ? bootfile : "kernel", msg);
+	/* Prepend the application name to the message if provided. */
+	if (app_name != NULL) {
+		if (procid != NULL)
+			msglen = snprintf(buf, sizeof(buf), "%s[%s]: %s",
+			    app_name, procid, msg);
+		else
+			msglen = snprintf(buf, sizeof(buf), "%s: %s",
+			    app_name, msg);
 		msg = buf;
-	}
-	msglen = strlen(msg);
+	} else
+		msglen = strlen(msg);
 
 	/* log the message to the particular outputs */
 	if (!Initialized) {
@@ -1152,8 +1465,7 @@ logmsg(int pri, const char *timestamp, const char *msg
 		f->f_file = open(ctty, O_WRONLY | O_NONBLOCK, 0);
 
 		if (f->f_file >= 0) {
-			(void)strlcpy(f->f_lasttime, timestamp,
-				sizeof(f->f_lasttime));
+			f->f_lasttime = *timestamp;
 			fprintlog(f, flags, msg);
 			close(f->f_file);
 			f->f_file = -1;
@@ -1174,7 +1486,8 @@ logmsg(int pri, const char *timestamp, const char *msg
 			continue;
 
 		/* skip messages with the incorrect program name */
-		if (skip_message(prog, f->f_program, 1))
+		if (skip_message(app_name == NULL ? "" : app_name,
+		    f->f_program, 1))
 			continue;
 
 		/* skip message to console if it has already been printed */
@@ -1192,8 +1505,7 @@ logmsg(int pri, const char *timestamp, const char *msg
 		    (flags & MARK) == 0 && msglen == f->f_prevlen &&
 		    !strcmp(msg, f->f_prevline) &&
 		    !strcasecmp(from, f->f_prevhost)) {
-			(void)strlcpy(f->f_lasttime, timestamp,
-				sizeof(f->f_lasttime));
+			f->f_lasttime = *timestamp;
 			f->f_prevcount++;
 			dprintf("msg repeated %d times, %ld sec of %d\n",
 			    f->f_prevcount, (long)(now - f->f_time),
@@ -1214,8 +1526,7 @@ logmsg(int pri, const char *timestamp, const char *msg
 				fprintlog(f, 0, (char *)NULL);
 			f->f_repeatcount = 0;
 			f->f_prevpri = pri;
-			(void)strlcpy(f->f_lasttime, timestamp,
-				sizeof(f->f_lasttime));
+			f->f_lasttime = *timestamp;
 			(void)strlcpy(f->f_prevhost, from,
 			    sizeof(f->f_prevhost));
 			if (msglen < MAXSVLINE) {
@@ -1254,8 +1565,12 @@ fprintlog(struct filed *f, int flags, const char *msg)
 	int l, lsent = 0;
 	char line[MAXLINE + 1], repbuf[80], greetings[200], *wmsg = NULL;
 	char nul[] = "", space[] = " ", lf[] = "\n", crlf[] = "\r\n";
+	char timebuf[RFC3164_DATELEN + 1];
 	const char *msgret;
 
+	if (strftime(timebuf, sizeof(timebuf), RFC3164_DATEFMT,
+	    &f->f_lasttime.tm) == 0)
+		timebuf[0] = '\0';
 	if (f->f_type == F_WALL) {
 		/* The time displayed is not synchornized with the other log
 		 * destinations (like messages).  Following fragment was using
@@ -1267,7 +1582,7 @@ fprintlog(struct filed *f, int flags, const char *msg)
 			.iov_len = snprintf(greetings, sizeof(greetings),
 				    "\r\n\7Message from syslogd@%s "
 				    "at %.24s ...\r\n",
-				    f->f_prevhost, f->f_lasttime)
+				    f->f_prevhost, timebuf)
 		};
 		if (iov[0].iov_len >= sizeof(greetings))
 			iov[0].iov_len = sizeof(greetings) - 1;
@@ -1277,8 +1592,8 @@ fprintlog(struct filed *f, int flags, const char *msg)
 		};
 	} else {
 		iov[0] = (struct iovec){
-			.iov_base = f->f_lasttime,
-			.iov_len = strlen(f->f_lasttime)
+			.iov_base = timebuf,
+			.iov_len = strlen(timebuf)
 		};
 		iov[1] = (struct iovec){
 			.iov_base = space,
@@ -1690,7 +2005,8 @@ logerror(const char *type)
 		(void)snprintf(buf, sizeof buf, "syslogd: %s", type);
 	errno = 0;
 	dprintf("%s\n", buf);
-	logmsg(LOG_SYSLOG|LOG_ERR, NULL, buf, LocalHostName, 0);
+	logmsg(LOG_SYSLOG|LOG_ERR, NULL, LocalHostName, NULL, NULL, NULL,
+	    NULL, buf, 0);
 	recursed--;
 }
 
@@ -2037,7 +2353,8 @@ init(int signo)
 		}
 	}
 
-	logmsg(LOG_SYSLOG|LOG_INFO, NULL, "syslogd: restart", LocalHostName, 0);
+	logmsg(LOG_SYSLOG|LOG_INFO, NULL, LocalHostName, NULL, NULL, NULL,
+	    NULL, "syslogd: restart", 0);
 	dprintf("syslogd: restarted\n");
 	/*
 	 * Log a change in hostname, but only on a restart.
@@ -2046,7 +2363,8 @@ init(int signo)
 		(void)snprintf(hostMsg, sizeof(hostMsg),
 		    "syslogd: hostname changed, \"%s\" to \"%s\"",
 		    oldLocalHostName, LocalHostName);
-		logmsg(LOG_SYSLOG|LOG_INFO, NULL, hostMsg, LocalHostName, 0);
+		logmsg(LOG_SYSLOG|LOG_INFO, NULL, LocalHostName, NULL, NULL,
+		    NULL, NULL, hostMsg, 0);
 		dprintf("%s\n", hostMsg);
 	}
 	/*
@@ -2056,7 +2374,8 @@ init(int signo)
 	if (signo == 0 && !use_bootfile) {
 		(void)snprintf(bootfileMsg, sizeof(bootfileMsg),
 		    "syslogd: kernel boot file is %s", bootfile);
-		logmsg(LOG_KERN|LOG_INFO, NULL, bootfileMsg, LocalHostName, 0);
+		logmsg(LOG_KERN|LOG_INFO, NULL, LocalHostName, NULL, NULL,
+		    NULL, NULL, bootfileMsg, 0);
 		dprintf("%s\n", bootfileMsg);
 	}
 }
@@ -2365,7 +2684,8 @@ markit(void)
 	now = time((time_t *)NULL);
 	MarkSeq += TIMERINTVL;
 	if (MarkSeq >= MarkInterval) {
-		logmsg(LOG_INFO, NULL, "-- MARK --", LocalHostName, MARK);
+		logmsg(LOG_INFO, NULL, LocalHostName, NULL, NULL, NULL, NULL,
+		    "-- MARK --", MARK);
 		MarkSeq = 0;
 	}
 


More information about the svn-src-all mailing list