From 889a08dc0ae0d6b76692e6ed811f431c5b5db53c Mon Sep 17 00:00:00 2001
From: Shiz <hi@shiz.me>
Date: Mon, 8 May 2017 23:09:13 +0200
Subject: [PATCH 11/16] sysklogd: add -Z option to adjust message timezones

Some syslog() implementations like musl's[1] always send timestamps in UTC.
This change adds a new option to syslogd, -Z, to assume incoming timestamps
are always UTC and adjust them to the local timezone (of the syslogd) before
logging.

[1]: http://www.openwall.com/lists/musl/2014/01/29/1

Signed-off-by: Shiz <hi@shiz.me>
---
 sysklogd/syslogd.c | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c
index 4265f4f90..eca955891 100644
--- a/sysklogd/syslogd.c
+++ b/sysklogd/syslogd.c
@@ -122,6 +122,7 @@
 //usage:       "(this version of syslogd ignores /etc/syslog.conf)\n"
 //usage:	)
 //usage:     "\n	-n		Run in foreground"
+//usage:     "\n	-Z		Adjust incoming UTC times to local time"
 //usage:	IF_FEATURE_REMOTE_LOG(
 //usage:     "\n	-R HOST[:PORT]	Log to HOST:PORT (default PORT:514)"
 //usage:     "\n	-L		Log locally and via network (default is network only if -R)"
@@ -233,6 +234,8 @@ typedef struct logRule_t {
 	/*int markInterval;*/                   \
 	/* level of messages to be logged */    \
 	int logLevel;                           \
+	/* whether to adjust message timezone */\
+	int adjustTimezone;                     \
 IF_FEATURE_ROTATE_LOGFILE( \
 	/* max size of file before rotation */  \
 	unsigned logFileSize;                   \
@@ -316,6 +319,7 @@ enum {
 	OPTBIT_outfile, // -O
 	OPTBIT_loglevel, // -l
 	OPTBIT_small, // -S
+	OPTBIT_adjusttz, // -Z
 	IF_FEATURE_ROTATE_LOGFILE(OPTBIT_filesize   ,)	// -s
 	IF_FEATURE_ROTATE_LOGFILE(OPTBIT_rotatecnt  ,)	// -b
 	IF_FEATURE_REMOTE_LOG(    OPTBIT_remotelog  ,)	// -R
@@ -330,6 +334,7 @@ enum {
 	OPT_outfile     = 1 << OPTBIT_outfile ,
 	OPT_loglevel    = 1 << OPTBIT_loglevel,
 	OPT_small       = 1 << OPTBIT_small   ,
+	OPT_adjusttz    = 1 << OPTBIT_adjusttz,
 	OPT_filesize    = IF_FEATURE_ROTATE_LOGFILE((1 << OPTBIT_filesize   )) + 0,
 	OPT_rotatecnt   = IF_FEATURE_ROTATE_LOGFILE((1 << OPTBIT_rotatecnt  )) + 0,
 	OPT_remotelog   = IF_FEATURE_REMOTE_LOG(    (1 << OPTBIT_remotelog  )) + 0,
@@ -339,7 +344,7 @@ enum {
 	OPT_cfg         = IF_FEATURE_SYSLOGD_CFG(   (1 << OPTBIT_cfg        )) + 0,
 	OPT_kmsg        = IF_FEATURE_KMSG_SYSLOG(   (1 << OPTBIT_kmsg       )) + 0,
 };
-#define OPTION_STR "m:nO:l:S" \
+#define OPTION_STR "m:nO:l:SZ" \
 	IF_FEATURE_ROTATE_LOGFILE("s:" ) \
 	IF_FEATURE_ROTATE_LOGFILE("b:" ) \
 	IF_FEATURE_REMOTE_LOG(    "R:*") \
@@ -815,17 +820,23 @@ static void timestamp_and_log(int pri, char *msg, int len)
 {
 	char *timestamp;
 	time_t now;
+	struct tm nowtm = { .tm_isdst = 0 };
 
 	/* Jan 18 00:11:22 msg... */
 	/* 01234567890123456 */
 	if (len < 16 || msg[3] != ' ' || msg[6] != ' '
 	 || msg[9] != ':' || msg[12] != ':' || msg[15] != ' '
 	) {
-		time(&now);
+		now = time(NULL);
 		timestamp = ctime(&now) + 4; /* skip day of week */
 	} else {
-		now = 0;
-		timestamp = msg;
+		if (G.adjustTimezone && strptime(msg, "%b %e %T", &nowtm)) {
+			now = mktime(&nowtm) - timezone;
+			timestamp = ctime(&now) + 4; /* skip day of week */
+		} else {
+			now = 0;
+			timestamp = msg;
+		}
 		msg += 16;
 	}
 	timestamp[15] = '\0';
@@ -1129,6 +1140,10 @@ int syslogd_main(int argc UNUSED_PARAM, char **argv)
 	if (opts & OPT_loglevel) // -l
 		G.logLevel = xatou_range(opt_l, 1, 8);
 	//if (opts & OPT_small) // -S
+	if (opts & OPT_adjusttz) { // -Z
+		G.adjustTimezone = 1;
+		tzset();
+	}
 #if ENABLE_FEATURE_ROTATE_LOGFILE
 	if (opts & OPT_filesize) // -s
 		G.logFileSize = xatou_range(opt_s, 0, INT_MAX/1024) * 1024;
-- 
2.16.2