summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2015-03-05 15:20:50 +0100
committerKarel Zak <kzak@redhat.com>2015-03-12 10:16:07 +0100
commitc330264bd9ed2d5d92542302d98266b9919d16d9 (patch)
tree3fb2003448d807875dbb7c41a3f340a49de7f159
parentd9074f191e4a6057f51f3a0d4bd0973366e245e2 (diff)
downloadutil-linux-c330264bd9ed2d5d92542302d98266b9919d16d9.tar.gz
logger: fix invalid timestamp regression in local format
Since 1d57503378bdcd838365d625f6d2d0a09da9c29d logger no longer uses the syslog(3) call. The way the local timestamp is generated did not match the syslog(3) format. Most importantly, the month name is formatted based on the user's local. For example: $ ./logger --stderr test with logger 2.26.39-eb651-dirty <5>Mär 5 14:17:47 logger: test with logger 2.26.39-eb651-dirty "Mär" like in German "März" for "March". previously: $ logger --stderr test with logger 2.25.2 rger: test with logger 2.25.2 In the system log file, this results to the following: Mar 5 14:17:47 host Mär 5 14:17:47 logger: test with logger 2.26.39-eb651-dirty Mar 5 14:18:01 host rger: test with logger 2.25.2 This local naming is invalid as of RFC3164. One may argue that the local log socket traditionally does not have RFC3164 format, but the timestamp always was as defined in RFC3164 (and along the lines of the ctime() call). Anything else would also be impractical, as a syslog parser would otherwise need to know about all potential locale-specific representations of month names. This patch corrects the problem and also refactors the timestamp handling a bit. The same timestamp is needed in local and rfc3164 processing, so there now is a new function to create that stamp.
-rw-r--r--misc-utils/logger.c42
1 files changed, 29 insertions, 13 deletions
diff --git a/misc-utils/logger.c b/misc-utils/logger.c
index 6b7ce1b83..6578cc702 100644
--- a/misc-utils/logger.c
+++ b/misc-utils/logger.c
@@ -306,9 +306,33 @@ static char *xgetlogin(void)
return cp;
}
+
+/* this creates a timestamp based on current time according to the
+ * fine rules of RFC3164, most importantly it ensures in a portable
+ * way that the month day is correctly written (with a SP instead
+ * of a leading 0). The function uses a static buffer which is
+ * overwritten on the next call (just like ctime() does).
+ */
+static const char *
+rfc3164_current_time(void)
+{
+ static char time[32];
+ struct timeval tv;
+ struct tm *tm;
+ static char *monthnames[] = { "Jan", "Feb", "Mar", "Apr",
+ "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+ gettimeofday(&tv, NULL);
+ tm = localtime(&tv.tv_sec);
+ snprintf(time, sizeof(time),"%s %2d %2.2d:%2.2d:%2.2d",
+ monthnames[tm->tm_mon], tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ return time;
+}
+
static void syslog_rfc3164(const struct logger_ctl *ctl, const char *msg)
{
- char *buf, pid[30], *cp, *tp, *hostname, *dot;
+ char *buf, pid[30], *cp, *hostname, *dot;
time_t now;
int len;
@@ -325,11 +349,8 @@ static void syslog_rfc3164(const struct logger_ctl *ctl, const char *msg)
if (dot)
*dot = '\0';
- time(&now);
- tp = ctime(&now) + 4;
-
len = xasprintf(&buf, "<%d>%.15s %s %.200s%s: %.400s",
- ctl->pri, tp, hostname, cp, pid, msg);
+ ctl->pri, rfc3164_current_time(), hostname, cp, pid, msg);
if (write_all(ctl->fd, buf, len) < 0)
warn(_("write failed"));
@@ -449,15 +470,9 @@ static int parse_unix_socket_errors_flags(char *optarg)
static void syslog_local(const struct logger_ctl *ctl, const char *msg)
{
char *buf, *tag;
- char time[32], pid[32];
- struct timeval tv;
- struct tm *tm;
+ char pid[32];
int len;
- gettimeofday(&tv, NULL);
- tm = localtime(&tv.tv_sec);
- strftime(time, sizeof(time), "%h %e %T", tm);
-
tag = ctl->tag ? ctl->tag : program_invocation_short_name;
if (ctl->pid)
@@ -465,7 +480,8 @@ static void syslog_local(const struct logger_ctl *ctl, const char *msg)
else
pid[0] = '\0';
- len = xasprintf(&buf, "<%d>%s %s%s: %s", ctl->pri, time, tag, pid, msg);
+ len = xasprintf(&buf, "<%d>%s %s%s: %s", ctl->pri, rfc3164_current_time(),
+ tag, pid, msg);
if (write_all(ctl->fd, buf, len) < 0)
warn(_("write failed"));
if (ctl->stderr_printout)