diff --git a/CHANGES b/CHANGES
index 60559a6cd5..0e18b48abe 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,10 @@
+4518. [func] The "print-time" option in the logging configuration
+ can now take arguments "local", "iso8601" or
+ "iso8601-utc" to indicate the format in which the
+ date and time should be logged. For backward
+ compatibility, "yes" is a synonym for "local".
+ [RT #42585]
+
4517. [placeholder]
4516. [bug] isc_socketmgr_renderjson was missing from the
diff --git a/bin/named/logconf.c b/bin/named/logconf.c
index a96a35b537..02d4dec39f 100644
--- a/bin/named/logconf.c
+++ b/bin/named/logconf.c
@@ -87,8 +87,7 @@ category_fromconf(const cfg_obj_t *ccat, isc_logconfig_t *logconfig) {
* in 'cchan' and add it to 'logconfig'.
*/
static isc_result_t
-channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *logconfig)
-{
+channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *logconfig) {
isc_result_t result;
isc_logdestination_t dest;
unsigned int type;
@@ -202,12 +201,21 @@ channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *logconfig)
if (printcat != NULL && cfg_obj_asboolean(printcat))
flags |= ISC_LOG_PRINTCATEGORY;
- if (printtime != NULL && cfg_obj_asboolean(printtime))
- flags |= ISC_LOG_PRINTTIME;
if (printsev != NULL && cfg_obj_asboolean(printsev))
flags |= ISC_LOG_PRINTLEVEL;
if (buffered != NULL && cfg_obj_asboolean(buffered))
flags |= ISC_LOG_BUFFERED;
+ if (printtime != NULL && cfg_obj_isboolean(printtime)) {
+ if (cfg_obj_asboolean(printtime))
+ flags |= ISC_LOG_PRINTTIME;
+ } else if (printtime != NULL) { /* local/iso8601/iso8601-utc */
+ const char *s = cfg_obj_asstring(printtime);
+ flags |= ISC_LOG_PRINTTIME;
+ if (strcasecmp(s, "iso8601") == 0)
+ flags |= ISC_LOG_ISO8601;
+ else if (strcasecmp(s, "iso8601-utc") == 0)
+ flags |= ISC_LOG_ISO8601 | ISC_LOG_UTC;
+ }
}
level = ISC_LOG_INFO;
diff --git a/bin/tests/system/checkconf/bad-printtime.conf b/bin/tests/system/checkconf/bad-printtime.conf
new file mode 100644
index 0000000000..3ae0b4c46a
--- /dev/null
+++ b/bin/tests/system/checkconf/bad-printtime.conf
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+logging {
+ channel one {
+ file "one.out";
+ print-time bogus;
+ };
+};
diff --git a/bin/tests/system/checkconf/good-printtime.conf b/bin/tests/system/checkconf/good-printtime.conf
new file mode 100644
index 0000000000..700e349452
--- /dev/null
+++ b/bin/tests/system/checkconf/good-printtime.conf
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+logging {
+ channel one {
+ file "one.out";
+ print-time no;
+ };
+ channel two {
+ file "two.out";
+ print-time yes;
+ };
+ channel three {
+ file "three.out";
+ print-time local;
+ };
+ channel four {
+ file "four.out";
+ print-time iso8601;
+ };
+ channel five {
+ file "five.out";
+ print-time iso8601-utc;
+ };
+};
diff --git a/bin/tests/system/logfileconfig/clean.sh b/bin/tests/system/logfileconfig/clean.sh
index 002d0ac255..14b4ab3078 100644
--- a/bin/tests/system/logfileconfig/clean.sh
+++ b/bin/tests/system/logfileconfig/clean.sh
@@ -6,8 +6,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-# $Id: clean.sh,v 1.4 2011/03/22 16:51:50 smann Exp $
-
#
# Clean up after log file tests
#
@@ -19,4 +17,6 @@ rm -rf ns1/named_dir
rm -f ns1/named_deflog
rm -f ns*/named.lock
rm -f ns1/query_log
+rm -f ns1/named_iso8601
+rm -f ns1/named_iso8601_utc
rm -f ns1/rndc.out.test*
diff --git a/bin/tests/system/logfileconfig/ns1/named.iso8601 b/bin/tests/system/logfileconfig/ns1/named.iso8601
new file mode 100644
index 0000000000..3040855a81
--- /dev/null
+++ b/bin/tests/system/logfileconfig/ns1/named.iso8601
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+options {
+ query-source address 10.53.0.1;
+ notify-source 10.53.0.1;
+ transfer-source 10.53.0.1;
+ port 5300;
+ pid-file "named.pid";
+ listen-on port 5300 {
+ 10.53.0.1;
+ };
+ listen-on-v6 { none; };
+ recursion no;
+ notify yes;
+};
+
+logging {
+ channel default_log {
+ file "named_iso8601";
+ print-time iso8601;
+ severity debug 9;
+ };
+ category default { default_log; default_debug; };
+};
+
+controls {
+ inet 127.0.0.1 port 9593
+ allow { 127.0.0.1/32; ::1/128; }
+ keys { "rndc-key"; };
+};
+
+key "rndc-key" {
+ algorithm hmac-sha256;
+ secret "Am9vCg==";
+};
+
+zone "." {
+ type master;
+ file "root.db";
+};
diff --git a/bin/tests/system/logfileconfig/ns1/named.iso8601-utc b/bin/tests/system/logfileconfig/ns1/named.iso8601-utc
new file mode 100644
index 0000000000..14241c7135
--- /dev/null
+++ b/bin/tests/system/logfileconfig/ns1/named.iso8601-utc
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+options {
+ query-source address 10.53.0.1;
+ notify-source 10.53.0.1;
+ transfer-source 10.53.0.1;
+ port 5300;
+ pid-file "named.pid";
+ listen-on port 5300 {
+ 10.53.0.1;
+ };
+ listen-on-v6 { none; };
+ recursion no;
+ notify yes;
+};
+
+logging {
+ channel default_log {
+ file "named_iso8601_utc";
+ print-time iso8601-utc;
+ severity debug 9;
+ };
+ category default { default_log; default_debug; };
+};
+
+controls {
+ inet 127.0.0.1 port 9593
+ allow { 127.0.0.1/32; ::1/128; }
+ keys { "rndc-key"; };
+};
+
+key "rndc-key" {
+ algorithm hmac-sha256;
+ secret "Am9vCg==";
+};
+
+zone "." {
+ type master;
+ file "root.db";
+};
diff --git a/bin/tests/system/logfileconfig/tests.sh b/bin/tests/system/logfileconfig/tests.sh
index b2acd3652e..44ef045143 100644
--- a/bin/tests/system/logfileconfig/tests.sh
+++ b/bin/tests/system/logfileconfig/tests.sh
@@ -12,16 +12,19 @@ SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
THISDIR=`pwd`
CONFDIR="ns1"
-PLAINCONF="${THISDIR}/${CONFDIR}/named.plain"
DIRCONF="${THISDIR}/${CONFDIR}/named.dirconf"
PIPECONF="${THISDIR}/${CONFDIR}/named.pipeconf"
SYMCONF="${THISDIR}/${CONFDIR}/named.symconf"
PLAINCONF="${THISDIR}/${CONFDIR}/named.plainconf"
+ISOCONF="${THISDIR}/${CONFDIR}/named.iso8601"
+ISOCONFUTC="${THISDIR}/${CONFDIR}/named.iso8601-utc"
PLAINFILE="named_log"
DIRFILE="named_dir"
PIPEFILE="named_pipe"
SYMFILE="named_sym"
DLFILE="named_deflog"
+ISOFILE="named_iso8601"
+ISOUTCFILE="named_iso8601_utc"
PIDFILE="${THISDIR}/${CONFDIR}/named.pid"
myRNDC="$RNDC -c ${THISDIR}/${CONFDIR}/rndc.conf"
myNAMED="$NAMED -c ${THISDIR}/${CONFDIR}/named.conf -m record,size,mctx -T clienttest -T nosyslog -d 99 -X named.lock -U 4"
@@ -238,10 +241,8 @@ else
echo "I: skipping symlink test (unable to create symlink)"
fi
-status=0
-
n=`expr $n + 1`
-echo "I:testing default logfile using named -L file ($n)"
+echo "I: testing default logfile using named -L file ($n)"
# Now stop the server again and test the -L option
rm -f $DLFILE
$PERL ../../stop.pl .. ns1
@@ -270,5 +271,29 @@ else
exit 1
fi
+echo "I:testing logging functionality"
+
+n=`expr $n + 1`
+echo "I: testing iso8601 timestamp ($n)"
+cp $ISOCONF named.conf
+$myRNDC reconfig > rndc.out.test$n 2>&1
+if grep '^....-..-..T..:..:..\.... ' $ISOFILE > /dev/null; then
+ echo "I: testing iso8601 timestamp succeeded"
+else
+ echo "I: testing iso8601 timestamp failed"
+ status=`expr $status + 1`
+fi
+
+n=`expr $n + 1`
+echo "I: testing iso8601-utc timestamp ($n)"
+cp $ISOCONFUTC named.conf
+$myRNDC reconfig > rndc.out.test$n 2>&1
+if grep '^....-..-..T..:..:..\....Z' $ISOUTCFILE > /dev/null; then
+ echo "I: testing iso8601-utc timestamp succeeded"
+else
+ echo "I: testing iso8601-utc timestamp failed"
+ status=`expr $status + 1`
+fi
+
echo "I:exit status: $status"
[ $status -eq 0 ] || exit 1
diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml
index 17d8272a47..9681c9cbcf 100644
--- a/doc/arm/Bv9ARM-book.xml
+++ b/doc/arm/Bv9ARM-book.xml
@@ -3644,7 +3644,7 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
| [ level ] | ); ]
[ print-category or ; ]
[ print-severity or ; ]
- [ print-time or ; ]
+ [ print-time ( | | | | ) ;
[ buffered or ; ]
}; ]
[ category category_name {
@@ -3877,14 +3877,30 @@ notrace. All debugging messages in the server have a debug
server's global debug level to determine what messages to print.
- If print-time has been turned on,
- then
- the date and time will be logged. print-time may
+ print-time can be set to
+ yes, no,
+ or a time format specifier, which may be one of
+ , or
+ . If set to
+ no, then the date and time will
+ not be logged. If set to yes
+ or , the date and time are logged
+ in a human readable format, using the local time zone.
+ If set to the local time is
+ logged in ISO8601 format. If set to
+ , then the date and time
+ are logged in ISO8601 format, with time zone set to
+ UTC. The default is .
+
+
+ print-time may
be specified for a syslog channel,
- but is usually
+ but it is usually
pointless since syslog also logs
- the date and
- time. If print-category is
+ the date and time.
+
+
+ If print-category is
requested, then the
category of the message will be logged as well. Finally, if print-severity is
on, then the severity level of the message will be logged. The print- options may
diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml
index af94d3089d..17220730d7 100644
--- a/doc/arm/notes.xml
+++ b/doc/arm/notes.xml
@@ -39,9 +39,10 @@
Added the ability to specify the maximum number of records
- permitted in a zone (max-records #;). This provides a mechanism
- to block overly large zone transfers, which is a potential risk
- with slave zones from other parties, as described in CVE-2016-6170.
+ permitted in a zone ().
+ This provides a mechanism to block overly large zone
+ transfers, which is a potential risk with slave zones from
+ other parties, as described in CVE-2016-6170.
[RT #42143]
@@ -52,7 +53,13 @@
- None.
+ The option in the
+ configuration can now take arguments
+ local, iso8601 or
+ iso8601-utc to indicate the format in
+ which the date and time should be logged. For backward
+ compatibility, yes is a synonym for
+ local. [RT #42585]
diff --git a/lib/isc/include/isc/log.h b/lib/isc/include/isc/log.h
index 7780abf3da..e77bafd0ef 100644
--- a/lib/isc/include/isc/log.h
+++ b/lib/isc/include/isc/log.h
@@ -54,16 +54,18 @@
/*%
* Channel flags.
*/
-#define ISC_LOG_PRINTTIME 0x0001
-#define ISC_LOG_PRINTLEVEL 0x0002
-#define ISC_LOG_PRINTCATEGORY 0x0004
-#define ISC_LOG_PRINTMODULE 0x0008
-#define ISC_LOG_PRINTTAG 0x0010 /* tag and ":" */
-#define ISC_LOG_PRINTPREFIX 0x0020 /* tag only, no colon */
-#define ISC_LOG_PRINTALL 0x003F
-#define ISC_LOG_BUFFERED 0x0040
-#define ISC_LOG_DEBUGONLY 0x1000
-#define ISC_LOG_OPENERR 0x8000 /* internal */
+#define ISC_LOG_PRINTTIME 0x00001
+#define ISC_LOG_PRINTLEVEL 0x00002
+#define ISC_LOG_PRINTCATEGORY 0x00004
+#define ISC_LOG_PRINTMODULE 0x00008
+#define ISC_LOG_PRINTTAG 0x00010 /* tag and ":" */
+#define ISC_LOG_PRINTPREFIX 0x00020 /* tag only, no colon */
+#define ISC_LOG_PRINTALL 0x0003F
+#define ISC_LOG_BUFFERED 0x00040
+#define ISC_LOG_DEBUGONLY 0x01000
+#define ISC_LOG_OPENERR 0x08000 /* internal */
+#define ISC_LOG_ISO8601 0x10000 /* if PRINTTIME, use ISO8601 */
+#define ISC_LOG_UTC 0x20000 /* if PRINTTIME, use UTC */
/*@}*/
/*@{*/
diff --git a/lib/isc/log.c b/lib/isc/log.c
index 337a0d90d5..f5b1a1feac 100644
--- a/lib/isc/log.c
+++ b/lib/isc/log.c
@@ -697,7 +697,8 @@ isc_log_createchannel(isc_logconfig_t *lcfg, const char *name,
isc_logchannel_t *channel;
isc_mem_t *mctx;
unsigned int permitted = ISC_LOG_PRINTALL | ISC_LOG_DEBUGONLY |
- ISC_LOG_BUFFERED;
+ ISC_LOG_BUFFERED | ISC_LOG_ISO8601 |
+ ISC_LOG_UTC;
REQUIRE(VALID_CONFIG(lcfg));
REQUIRE(name != NULL);
@@ -1396,12 +1397,15 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
const char *format, va_list args)
{
int syslog_level;
- char time_string[64];
+ const char *time_string;
+ char local_time[64];
+ char iso8601z_string[64];
+ char iso8601l_string[64];
char level_string[24];
const char *iformat;
struct stat statbuf;
isc_boolean_t matched = ISC_FALSE;
- isc_boolean_t printtime, printtag, printcolon;
+ isc_boolean_t printtime, iso8601, utc, printtag, printcolon;
isc_boolean_t printcategory, printmodule, printlevel, buffered;
isc_logconfig_t *lcfg;
isc_logchannel_t *channel;
@@ -1433,7 +1437,9 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
else
iformat = format;
- time_string[0] = '\0';
+ local_time[0] = '\0';
+ iso8601l_string[0] = '\0';
+ iso8601z_string[0] = '\0';
level_string[0] = '\0';
LOCK(&lctx->lock);
@@ -1496,12 +1502,21 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
continue;
if ((channel->flags & ISC_LOG_PRINTTIME) != 0 &&
- time_string[0] == '\0') {
+ local_time[0] == '\0')
+ {
isc_time_t isctime;
TIME_NOW(&isctime);
- isc_time_formattimestamp(&isctime, time_string,
- sizeof(time_string));
+
+ isc_time_formattimestamp(&isctime,
+ local_time,
+ sizeof(local_time));
+ isc_time_formatISO8601ms(&isctime,
+ iso8601z_string,
+ sizeof(iso8601z_string));
+ isc_time_formatISO8601Lms(&isctime,
+ iso8601l_string,
+ sizeof(iso8601l_string));
}
if ((channel->flags & ISC_LOG_PRINTLEVEL) != 0 &&
@@ -1628,6 +1643,8 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
}
}
+ utc = ISC_TF((channel->flags & ISC_LOG_UTC) != 0);
+ iso8601 = ISC_TF((channel->flags & ISC_LOG_ISO8601) != 0);
printtime = ISC_TF((channel->flags & ISC_LOG_PRINTTIME)
!= 0);
printtag = ISC_TF((channel->flags &
@@ -1644,6 +1661,19 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
buffered = ISC_TF((channel->flags & ISC_LOG_BUFFERED)
!= 0);
+ if (printtime) {
+ if (iso8601) {
+ if (utc) {
+ time_string = iso8601z_string;
+ } else {
+ time_string = iso8601l_string;
+ }
+ } else {
+ time_string = local_time;
+ }
+ } else
+ time_string = "";
+
switch (channel->type) {
case ISC_LOG_TOFILE:
if (FILE_MAXREACHED(channel)) {
@@ -1691,7 +1721,7 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
case ISC_LOG_TOFILEDESC:
fprintf(FILE_STREAM(channel),
"%s%s%s%s%s%s%s%s%s%s\n",
- printtime ? time_string : "",
+ printtime ? time_string : "",
printtime ? " " : "",
printtag ? lcfg->tag : "",
printcolon ? ": " : "",
diff --git a/lib/isc/tests/time_test.c b/lib/isc/tests/time_test.c
index 810c77c6e7..46109dc3c8 100644
--- a/lib/isc/tests/time_test.c
+++ b/lib/isc/tests/time_test.c
@@ -8,6 +8,7 @@
#include
#include
+#include
#include
@@ -33,11 +34,118 @@ ATF_TC_BODY(isc_time_parsehttptimestamp, tc) {
ATF_REQUIRE_EQ(isc_time_seconds(&t), isc_time_seconds(&x));
}
+ATF_TC(isc_time_formatISO8601);
+ATF_TC_HEAD(isc_time_formatISO8601, tc) {
+ atf_tc_set_md_var(tc, "descr", "print UTC in ISO8601");
+}
+ATF_TC_BODY(isc_time_formatISO8601, tc) {
+ isc_result_t result;
+ isc_time_t t;
+ char buf[64];
+
+ setenv("TZ", "PST8PDT", 1);
+ result = isc_time_now(&t);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /* yyyy-mm-ddThh:mm:ssZ */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_formatISO8601(&t, buf, sizeof(buf));
+ ATF_CHECK_EQ(strlen(buf), 20);
+ ATF_CHECK_EQ(buf[4], '-');
+ ATF_CHECK_EQ(buf[7], '-');
+ ATF_CHECK_EQ(buf[10], 'T');
+ ATF_CHECK_EQ(buf[13], ':');
+ ATF_CHECK_EQ(buf[16], ':');
+ ATF_CHECK_EQ(buf[19], 'Z');
+}
+
+ATF_TC(isc_time_formatISO8601ms);
+ATF_TC_HEAD(isc_time_formatISO8601ms, tc) {
+ atf_tc_set_md_var(tc, "descr",
+ "print UTC in ISO8601 with milliseconds");
+}
+ATF_TC_BODY(isc_time_formatISO8601ms, tc) {
+ isc_result_t result;
+ isc_time_t t;
+ char buf[64];
+
+ setenv("TZ", "PST8PDT", 1);
+ result = isc_time_now(&t);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /* yyyy-mm-ddThh:mm:ss.sssZ */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_formatISO8601ms(&t, buf, sizeof(buf));
+ ATF_CHECK_EQ(strlen(buf), 24);
+ ATF_CHECK_EQ(buf[4], '-');
+ ATF_CHECK_EQ(buf[7], '-');
+ ATF_CHECK_EQ(buf[10], 'T');
+ ATF_CHECK_EQ(buf[13], ':');
+ ATF_CHECK_EQ(buf[16], ':');
+ ATF_CHECK_EQ(buf[19], '.');
+ ATF_CHECK_EQ(buf[23], 'Z');
+}
+
+ATF_TC(isc_time_formatISO8601L);
+ATF_TC_HEAD(isc_time_formatISO8601L, tc) {
+ atf_tc_set_md_var(tc, "descr",
+ "print local time in ISO8601");
+}
+ATF_TC_BODY(isc_time_formatISO8601L, tc) {
+ isc_result_t result;
+ isc_time_t t;
+ char buf[64];
+
+ setenv("TZ", "PST8PDT", 1);
+ result = isc_time_now(&t);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /* yyyy-mm-ddThh:mm:ss */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_formatISO8601L(&t, buf, sizeof(buf));
+ ATF_CHECK_EQ(strlen(buf), 19);
+ ATF_CHECK_EQ(buf[4], '-');
+ ATF_CHECK_EQ(buf[7], '-');
+ ATF_CHECK_EQ(buf[10], 'T');
+ ATF_CHECK_EQ(buf[13], ':');
+ ATF_CHECK_EQ(buf[16], ':');
+}
+
+ATF_TC(isc_time_formatISO8601Lms);
+ATF_TC_HEAD(isc_time_formatISO8601Lms, tc) {
+ atf_tc_set_md_var(tc, "descr",
+ "print local time in ISO8601 with milliseconds");
+}
+ATF_TC_BODY(isc_time_formatISO8601Lms, tc) {
+ isc_result_t result;
+ isc_time_t t;
+ char buf[64];
+
+ setenv("TZ", "PST8PDT", 1);
+ result = isc_time_now(&t);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /* yyyy-mm-ddThh:mm:ss.sss */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_formatISO8601Lms(&t, buf, sizeof(buf));
+ ATF_CHECK_EQ(strlen(buf), 23);
+ ATF_CHECK_EQ(buf[4], '-');
+ ATF_CHECK_EQ(buf[7], '-');
+ ATF_CHECK_EQ(buf[10], 'T');
+ ATF_CHECK_EQ(buf[13], ':');
+ ATF_CHECK_EQ(buf[16], ':');
+ ATF_CHECK_EQ(buf[19], '.');
+}
+
/*
* Main
*/
ATF_TP_ADD_TCS(tp) {
ATF_TP_ADD_TC(tp, isc_time_parsehttptimestamp);
+ ATF_TP_ADD_TC(tp, isc_time_formatISO8601);
+ ATF_TP_ADD_TC(tp, isc_time_formatISO8601ms);
+ ATF_TP_ADD_TC(tp, isc_time_formatISO8601L);
+ ATF_TP_ADD_TC(tp, isc_time_formatISO8601Lms);
return (atf_no_error());
}
diff --git a/lib/isc/unix/include/isc/time.h b/lib/isc/unix/include/isc/time.h
index 939db5d761..47ccd53098 100644
--- a/lib/isc/unix/include/isc/time.h
+++ b/lib/isc/unix/include/isc/time.h
@@ -323,6 +323,34 @@ isc_time_parsehttptimestamp(char *input, isc_time_t *t);
*\li 'buf' and 't' are not NULL.
*/
+void
+isc_time_formatISO8601L(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formatISO8601Lms(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.sss"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
void
isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len);
/*%<
diff --git a/lib/isc/unix/time.c b/lib/isc/unix/time.c
index 59008466de..f7d40306f0 100644
--- a/lib/isc/unix/time.c
+++ b/lib/isc/unix/time.c
@@ -424,6 +424,34 @@ isc_time_parsehttptimestamp(char *buf, isc_time_t *t) {
return (ISC_R_SUCCESS);
}
+void
+isc_time_formatISO8601L(const isc_time_t *t, char *buf, unsigned int len) {
+ time_t now;
+ unsigned int flen;
+
+ REQUIRE(len > 0);
+
+ now = (time_t)t->seconds;
+ flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", localtime(&now));
+ INSIST(flen < len);
+}
+
+void
+isc_time_formatISO8601Lms(const isc_time_t *t, char *buf, unsigned int len) {
+ time_t now;
+ unsigned int flen;
+
+ REQUIRE(len > 0);
+
+ now = (time_t)t->seconds;
+ flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", localtime(&now));
+ INSIST(flen < len);
+ if (flen > 0U && len - flen >= 6) {
+ snprintf(buf + flen, len - flen, ".%03u",
+ t->nanoseconds / NS_PER_MS);
+ }
+}
+
void
isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) {
time_t now;
@@ -446,8 +474,8 @@ isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len) {
now = (time_t)t->seconds;
flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
INSIST(flen < len);
- if (flen == len - 5) {
- flen -= 1; /* rewind one character */
+ if (flen > 0U && len - flen >= 5) {
+ flen -= 1; /* rewind one character (Z) */
snprintf(buf + flen, len - flen, ".%03uZ",
t->nanoseconds / NS_PER_MS);
}
diff --git a/lib/isc/win32/include/isc/time.h b/lib/isc/win32/include/isc/time.h
index 4e10a3837e..4b244dba95 100644
--- a/lib/isc/win32/include/isc/time.h
+++ b/lib/isc/win32/include/isc/time.h
@@ -287,6 +287,34 @@ isc_time_parsehttptimestamp(char *input, isc_time_t *t);
*\li 'buf' and 't' are not NULL.
*/
+void
+isc_time_formatISO8601L(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formatISO8601Lms(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.sss"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
void
isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len);
/*%<
diff --git a/lib/isc/win32/time.c b/lib/isc/win32/time.c
index eaeb69d80f..43e9a84ec1 100644
--- a/lib/isc/win32/time.c
+++ b/lib/isc/win32/time.c
@@ -328,6 +328,49 @@ isc_time_parsehttptimestamp(char *buf, isc_time_t *t) {
return (ISC_R_SUCCESS);
}
+void
+isc_time_formatISO8601L(const isc_time_t *t, char *buf, unsigned int len) {
+ SYSTEMTIME st;
+ char DateBuf[50];
+ char TimeBuf[50];
+
+ /* strtime() format: "%Y-%m-%dT%H:%M:%S" */
+
+ REQUIRE(len > 0);
+ if (FileTimeToSystemTime(&t->absolute, &st)) {
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "yyyy-MM-dd",
+ DateBuf, 50);
+ GetTimeFormat(LOCALE_USER_DEFAULT,
+ TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT,
+ &st, "hh':'mm':'ss", TimeBuf, 50);
+ snprintf(buf, len, "%sT%s", DateBuf, TimeBuf);
+ } else {
+ buf[0] = 0;
+ }
+}
+
+void
+isc_time_formatISO8601Lms(const isc_time_t *t, char *buf, unsigned int len) {
+ SYSTEMTIME st;
+ char DateBuf[50];
+ char TimeBuf[50];
+
+ /* strtime() format: "%Y-%m-%dT%H:%M:%S.SSS" */
+
+ REQUIRE(len > 0);
+ if (FileTimeToSystemTime(&t->absolute, &st)) {
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "yyyy-MM-dd",
+ DateBuf, 50);
+ GetTimeFormat(LOCALE_USER_DEFAULT,
+ TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT,
+ &st, "hh':'mm':'ss", TimeBuf, 50);
+ snprintf(buf, len, "%sT%s.%03u", DateBuf, TimeBuf,
+ st.wMilliseconds);
+ } else {
+ buf[0] = 0;
+ }
+}
+
void
isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) {
SYSTEMTIME st;
diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c
index 66c4ae2c7c..ee38ffc780 100644
--- a/lib/isccfg/namedconf.c
+++ b/lib/isccfg/namedconf.c
@@ -123,6 +123,7 @@ static cfg_type_t cfg_type_optional_port;
static cfg_type_t cfg_type_optional_uint32;
static cfg_type_t cfg_type_options;
static cfg_type_t cfg_type_portiplist;
+static cfg_type_t cfg_type_printtime;
static cfg_type_t cfg_type_querysource4;
static cfg_type_t cfg_type_querysource6;
static cfg_type_t cfg_type_querysource;
@@ -2070,7 +2071,6 @@ static cfg_type_t cfg_type_server = {
server_clausesets
};
-
/*%
* Clauses that can be found in a 'channel' clause in the
* 'logging' statement.
@@ -2078,8 +2078,24 @@ static cfg_type_t cfg_type_server = {
* These have some additional constraints that need to be
* checked after parsing:
* - There must exactly one of file/syslog/null/stderr
- *
*/
+
+static const char *printtime_enums[] = {
+ "local", "iso8601", "iso8601-utc", NULL
+};
+static isc_result_t
+parse_printtime(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
+}
+static void
+doc_printtime(cfg_printer_t *pctx, const cfg_type_t *type) {
+ doc_enum_or_other(pctx, type, &cfg_type_boolean);
+}
+static cfg_type_t cfg_type_printtime = {
+ "printtime", parse_printtime, cfg_print_ustring, doc_printtime,
+ &cfg_rep_string, printtime_enums
+};
+
static cfg_clausedef_t
channel_clauses[] = {
/* Destinations. We no longer require these to be first. */
@@ -2089,7 +2105,7 @@ channel_clauses[] = {
{ "stderr", &cfg_type_void, 0 },
/* Options. We now accept these for the null channel, too. */
{ "severity", &cfg_type_logseverity, 0 },
- { "print-time", &cfg_type_boolean, 0 },
+ { "print-time", &cfg_type_printtime, 0 },
{ "print-severity", &cfg_type_boolean, 0 },
{ "print-category", &cfg_type_boolean, 0 },
{ "buffered", &cfg_type_boolean, 0 },