log: syslog driver
Provide a log driver that broadcasts RFC 3164 messages to syslog servers.
rsyslog is one implementation of such a server.
The messages are sent to the local broadcast address 255.255.255.255 on
port 514.
The environment variable log_hostname can be used to provide the HOSTNAME
field for the messages. The optional TIMESTAMP field of RFC 3164 is not
provided.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Simon Glass <sjg@chromium.org>
diff --git a/MAINTAINERS b/MAINTAINERS
index d8d420f..0bafe5c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -654,7 +654,7 @@
M: Simon Glass <sjg@chromium.org>
S: Maintained
T: git https://gitlab.denx.de/u-boot/u-boot.git
-F: common/log.c
+F: common/log*
F: cmd/log.c
F: test/log/log_test.c
F: test/py/tests/test_log.py
diff --git a/common/Kconfig b/common/Kconfig
index 40da8fa..ee4f748 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -775,6 +775,13 @@
log message is shown - other details like level, category, file and
line number are omitted.
+config LOG_SYSLOG
+ bool "Log output to syslog server"
+ depends on LOG && NET
+ help
+ Enables a log driver which broadcasts log records via UDP port 514
+ to syslog servers.
+
config LOG_TEST
bool "Provide a test for logging"
depends on LOG && UNIT_TEST
diff --git a/common/Makefile b/common/Makefile
index 702f239..d84e10b 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -132,6 +132,7 @@
obj-y += command.o
obj-$(CONFIG_$(SPL_TPL_)LOG) += log.o
obj-$(CONFIG_$(SPL_TPL_)LOG_CONSOLE) += log_console.o
+obj-$(CONFIG_$(SPL_TPL_)LOG_SYSLOG) += log_syslog.o
obj-y += s_record.o
obj-$(CONFIG_CMD_LOADB) += xyzModem.o
obj-$(CONFIG_$(SPL_TPL_)YMODEM_SUPPORT) += xyzModem.o
diff --git a/common/log_syslog.c b/common/log_syslog.c
new file mode 100644
index 0000000..5e3e20e
--- /dev/null
+++ b/common/log_syslog.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Log to syslog.
+ *
+ * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ */
+
+#include <common.h>
+#include <log.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define BUFFER_SIZE 480
+
+static void append(char **buf, char *buf_end, const char *fmt, ...)
+{
+ va_list args;
+ size_t size = buf_end - *buf;
+
+ va_start(args, fmt);
+ vsnprintf(*buf, size, fmt, args);
+ va_end(args);
+ *buf += strlen(*buf);
+}
+
+static int log_syslog_emit(struct log_device *ldev, struct log_rec *rec)
+{
+ int ret;
+ int fmt = gd->log_fmt;
+ char msg[BUFFER_SIZE];
+ char *msg_end = msg + BUFFER_SIZE;
+ char *ptr = msg;
+ char *iphdr;
+ char *log_msg;
+ int eth_hdr_size;
+ struct in_addr bcast_ip;
+ static int processing_msg;
+ unsigned int log_level;
+ char *log_hostname;
+
+ /* Fend off messages from the network stack while writing a message */
+ if (processing_msg)
+ return 0;
+
+ processing_msg = 1;
+
+ /* Setup packet buffers */
+ net_init();
+ /* Disable hardware and put it into the reset state */
+ eth_halt();
+ /* Set current device according to environment variables */
+ eth_set_current();
+ /* Get hardware ready for send and receive operations */
+ ret = eth_init();
+ if (ret < 0) {
+ eth_halt();
+ goto out;
+ }
+
+ memset(msg, 0, BUFFER_SIZE);
+
+ /* Set ethernet header */
+ eth_hdr_size = net_set_ether((uchar *)ptr, net_bcast_ethaddr, PROT_IP);
+ ptr += eth_hdr_size;
+ iphdr = ptr;
+ ptr += IP_UDP_HDR_SIZE;
+ log_msg = ptr;
+
+ /*
+ * The syslog log levels defined in RFC 5424 match the U-Boot ones up to
+ * level 7 (debug).
+ */
+ log_level = rec->level;
+ if (log_level > 7)
+ log_level = 7;
+ /* Leave high bits as 0 to write a 'kernel message' */
+
+ /* Write log message to buffer */
+ append(&ptr, msg_end, "<%u>", log_level);
+ log_hostname = env_get("log_hostname");
+ if (log_hostname)
+ append(&ptr, msg_end, "%s ", log_hostname);
+ append(&ptr, msg_end, "uboot: ");
+ if (fmt & (1 << LOGF_LEVEL))
+ append(&ptr, msg_end, "%s.",
+ log_get_level_name(rec->level));
+ if (fmt & (1 << LOGF_CAT))
+ append(&ptr, msg_end, "%s,",
+ log_get_cat_name(rec->cat));
+ if (fmt & (1 << LOGF_FILE))
+ append(&ptr, msg_end, "%s:", rec->file);
+ if (fmt & (1 << LOGF_LINE))
+ append(&ptr, msg_end, "%d-", rec->line);
+ if (fmt & (1 << LOGF_FUNC))
+ append(&ptr, msg_end, "%s()", rec->func);
+ if (fmt & (1 << LOGF_MSG))
+ append(&ptr, msg_end, "%s%s",
+ fmt != (1 << LOGF_MSG) ? " " : "", rec->msg);
+ /* Consider trailing 0x00 */
+ ptr++;
+
+ debug("log message: '%s'\n", log_msg);
+
+ /* Broadcast message */
+ bcast_ip.s_addr = 0xFFFFFFFFL;
+ net_set_udp_header((uchar *)iphdr, bcast_ip, 514, 514, ptr - log_msg);
+ net_send_packet((uchar *)msg, ptr - msg);
+
+out:
+ processing_msg = 0;
+ return ret;
+}
+
+LOG_DRIVER(syslog) = {
+ .name = "syslog",
+ .emit = log_syslog_emit,
+};
diff --git a/doc/README.log b/doc/README.log
index 19856d4..1057981 100644
--- a/doc/README.log
+++ b/doc/README.log
@@ -147,7 +147,10 @@
enabled or disabled independently:
console - goes to stdout
+ syslog - broadcast RFC 3164 messages to syslog servers on UDP port 514
+The syslog driver sends the value of environmental variable 'log_hostname' as
+HOSTNAME if available.
Log format
----------