1 From 63c2e7ecc0c7a72b2ed35475a8d18d3052039ce4 Mon Sep 17 00:00:00 2001
2 From: Jeremie Koenig <jk@jk.fr.eu.org>
3 Date: Sun, 1 Aug 2010 03:01:44 +0200
4 Subject: [PATCH 1/2] klogd: make it work on non-linux systems
6 The klogctl() interface allows changing the console loglevel, but is
7 Linux-specific. The more portable method of reading from _PATH_KLOG is
8 added as an alternative.
10 Adapted from the Debian kFreeBSD patch at:
11 http://svn.debian.org/viewsvn/d-i/people/slackydeb/kfreebsd/busybox/1.14/debian/klogd.diff
13 Signed-off-by: Jeremie Koenig <jk@jk.fr.eu.org>
14 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
16 sysklogd/Config.src | 17 ++++++-
17 sysklogd/klogd.c | 128 +++++++++++++++++++++++++++++++++++++++++++-------
18 2 files changed, 126 insertions(+), 19 deletions(-)
20 diff --git a/sysklogd/Config.src b/sysklogd/Config.src
21 index 41c0d28..1e59872 100644
22 --- a/sysklogd/Config.src
23 +++ b/sysklogd/Config.src
24 @@ -109,7 +109,6 @@ config FEATURE_LOGREAD_REDUCED_LOCKING
28 - depends on PLATFORM_LINUX
30 klogd is a utility which intercepts and logs all
31 messages from the Linux kernel and sends the messages
32 @@ -117,6 +116,22 @@ config KLOGD
33 you wish to record the messages produced by the kernel,
34 you should enable this option.
36 +config FEATURE_KLOGD_KLOGCTL
37 + bool "Use the klogctl() interface"
39 + depends on KLOGD && PLATFORM_LINUX
41 + The klogd applet supports two interfaces for reading
42 + kernel messages. Linux provides the klogctl() interface
43 + which allows reading messages from the kernel ring buffer
44 + independently from the file system.
46 + If you answer 'N' here, klogd will use the more portable
47 + approach of reading them from /proc or a device node.
48 + However, this method requires the file to be available.
50 + If in doubt, say 'Y'.
55 diff --git a/sysklogd/klogd.c b/sysklogd/klogd.c
56 index c54e80a..3468656 100644
57 --- a/sysklogd/klogd.c
58 +++ b/sysklogd/klogd.c
61 * Copyright (C) 2001 by Gennady Feldman <gfeldman@gena01.com>.
62 * Changes: Made this a standalone busybox module which uses standalone
63 - * syslog() client interface.
64 + * syslog() client interface.
66 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
72 -#include <sys/klog.h>
74 -static void klogd_signal(int sig)
76 +/* The Linux-specific klogctl(3) interface does not rely on the filesystem and
77 + * allows us to change the console loglevel. Alternatively, we read the
78 + * messages from _PATH_KLOG. */
80 +#if ENABLE_FEATURE_KLOGD_KLOGCTL
82 +# include <sys/klog.h>
84 +static void klogd_open(void)
86 + /* "Open the log. Currently a NOP" */
87 + klogctl(1, NULL, 0);
90 +static void klogd_setloglevel(int lvl)
92 + /* "printk() prints a message on the console only if it has a loglevel
93 + * less than console_loglevel". Here we set console_loglevel = lvl. */
94 + klogctl(8, NULL, lvl);
97 +static int klogd_read(char *bufp, int len)
99 + return klogctl(2, bufp, len);
101 +# define READ_ERROR "klogctl(2) error"
103 +static void klogd_close(void)
105 /* FYI: cmd 7 is equivalent to setting console_loglevel to 7
106 * via klogctl(8, NULL, 7). */
107 klogctl(7, NULL, 0); /* "7 -- Enable printk's to console" */
108 klogctl(0, NULL, 0); /* "0 -- Close the log. Currently a NOP" */
109 - syslog(LOG_NOTICE, "klogd: exiting");
110 - kill_myself_with_sig(sig);
118 +# define _PATH_KLOG "/dev/klog"
120 +# error "your system's _PATH_KLOG is unknown"
123 +# define PATH_PRINTK "/proc/sys/kernel/printk"
125 +enum { klogfd = 3 };
127 +static void klogd_open(void)
129 + int fd = xopen(_PATH_KLOG, O_RDONLY);
130 + xmove_fd(fd, klogfd);
133 +static void klogd_setloglevel(int lvl)
135 + FILE *fp = fopen_or_warn(PATH_PRINTK, "w");
137 + /* This changes only first value:
138 + * "messages with a higher priority than this
139 + * [that is, with numerically lower value]
140 + * will be printed to the console".
141 + * The other three values in this pseudo-file aren't changed.
143 + fprintf(fp, "%u\n", lvl);
148 +static int klogd_read(char *bufp, int len)
150 + return read(klogfd, bufp, len);
152 +# define READ_ERROR "read error"
154 +static void klogd_close(void)
156 + klogd_setloglevel(7);
157 + if (ENABLE_FEATURE_CLEAN_UP)
163 #define log_buffer bb_common_bufsiz1
165 KLOGD_LOGBUF_SIZE = sizeof(log_buffer),
166 @@ -38,6 +113,19 @@ enum {
167 OPT_FOREGROUND = (1 << 1),
170 +/* TODO: glibc openlog(LOG_KERN) reverts to LOG_USER instead,
171 + * because that's how they interpret word "default"
172 + * in the openlog() manpage:
173 + * LOG_USER (default)
174 + * generic user-level messages
175 + * and the fact that LOG_KERN is a constant 0.
176 + * glibc interprets it as "0 in openlog() call means 'use default'".
177 + * I think it means "if openlog wasn't called before syslog() is called,
179 + * Convincing glibc maintainers otherwise is, as usual, nearly impossible.
180 + * Should we open-code syslog() here to use correct facility?
183 int klogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
184 int klogd_main(int argc UNUSED_PARAM, char **argv)
186 @@ -55,34 +143,34 @@ int klogd_main(int argc UNUSED_PARAM, char **argv)
187 bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
190 - openlog("kernel", 0, LOG_KERN);
192 - bb_signals(BB_FATAL_SIGS, klogd_signal);
193 - signal(SIGHUP, SIG_IGN);
194 + logmode = LOGMODE_SYSLOG;
196 - /* "Open the log. Currently a NOP" */
197 - klogctl(1, NULL, 0);
198 + /* klogd_open() before openlog(), since it might use fixed fd 3,
199 + * and openlog() also may use the same fd 3 if we swap them:
202 + openlog("kernel", 0, LOG_KERN);
204 - /* "printk() prints a message on the console only if it has a loglevel
205 - * less than console_loglevel". Here we set console_loglevel = i. */
207 - klogctl(8, NULL, i);
208 + klogd_setloglevel(i);
210 + bb_signals(BB_FATAL_SIGS, record_signo);
211 + signal(SIGHUP, SIG_IGN);
213 syslog(LOG_NOTICE, "klogd started: %s", bb_banner);
216 + while (!bb_got_signal) {
221 /* "2 -- Read from the log." */
222 start = log_buffer + used;
223 - n = klogctl(2, start, KLOGD_LOGBUF_SIZE-1 - used);
224 + n = klogd_read(start, KLOGD_LOGBUF_SIZE-1 - used);
228 - syslog(LOG_ERR, "klogd: error %d in klogctl(2): %m",
230 + bb_perror_msg(READ_ERROR);
234 @@ -131,5 +219,9 @@ int klogd_main(int argc UNUSED_PARAM, char **argv)
239 + syslog(LOG_NOTICE, "klogd: exiting");
241 + kill_myself_with_sig(bb_got_signal);