aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremie Koenig <jk@jk.fr.eu.org>2010-08-01 03:01:44 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2010-08-01 03:01:44 +0200
commit63c2e7ecc0c7a72b2ed35475a8d18d3052039ce4 (patch)
tree502795272936f6225a3ae268d40dfbf80027c89f
parent17662801ece60bbcc45bbc3cb1fc0fc3070d0d23 (diff)
downloadbusybox-w32-63c2e7ecc0c7a72b2ed35475a8d18d3052039ce4.tar.gz
busybox-w32-63c2e7ecc0c7a72b2ed35475a8d18d3052039ce4.tar.bz2
busybox-w32-63c2e7ecc0c7a72b2ed35475a8d18d3052039ce4.zip
klogd: make it work on non-linux systems
The klogctl() interface allows changing the console loglevel, but is Linux-specific. The more portable method of reading from _PATH_KLOG is added as an alternative. Adapted from the Debian kFreeBSD patch at: http://svn.debian.org/viewsvn/d-i/people/slackydeb/kfreebsd/busybox/1.14/debian/klogd.diff Signed-off-by: Jeremie Koenig <jk@jk.fr.eu.org> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--sysklogd/Config.src17
-rw-r--r--sysklogd/klogd.c128
2 files changed, 126 insertions, 19 deletions
diff --git a/sysklogd/Config.src b/sysklogd/Config.src
index 41c0d286b..1e5987275 100644
--- a/sysklogd/Config.src
+++ b/sysklogd/Config.src
@@ -109,7 +109,6 @@ config FEATURE_LOGREAD_REDUCED_LOCKING
109config KLOGD 109config KLOGD
110 bool "klogd" 110 bool "klogd"
111 default y 111 default y
112 depends on PLATFORM_LINUX
113 help 112 help
114 klogd is a utility which intercepts and logs all 113 klogd is a utility which intercepts and logs all
115 messages from the Linux kernel and sends the messages 114 messages from the Linux kernel and sends the messages
@@ -117,6 +116,22 @@ config KLOGD
117 you wish to record the messages produced by the kernel, 116 you wish to record the messages produced by the kernel,
118 you should enable this option. 117 you should enable this option.
119 118
119config FEATURE_KLOGD_KLOGCTL
120 bool "Use the klogctl() interface"
121 default y
122 depends on KLOGD && PLATFORM_LINUX
123 help
124 The klogd applet supports two interfaces for reading
125 kernel messages. Linux provides the klogctl() interface
126 which allows reading messages from the kernel ring buffer
127 independently from the file system.
128
129 If you answer 'N' here, klogd will use the more portable
130 approach of reading them from /proc or a device node.
131 However, this method requires the file to be available.
132
133 If in doubt, say 'Y'.
134
120config LOGGER 135config LOGGER
121 bool "logger" 136 bool "logger"
122 default y 137 default y
diff --git a/sysklogd/klogd.c b/sysklogd/klogd.c
index c54e80a35..3468656cc 100644
--- a/sysklogd/klogd.c
+++ b/sysklogd/klogd.c
@@ -4,7 +4,7 @@
4 * 4 *
5 * Copyright (C) 2001 by Gennady Feldman <gfeldman@gena01.com>. 5 * Copyright (C) 2001 by Gennady Feldman <gfeldman@gena01.com>.
6 * Changes: Made this a standalone busybox module which uses standalone 6 * Changes: Made this a standalone busybox module which uses standalone
7 * syslog() client interface. 7 * syslog() client interface.
8 * 8 *
9 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 9 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
10 * 10 *
@@ -19,18 +19,93 @@
19 19
20#include "libbb.h" 20#include "libbb.h"
21#include <syslog.h> 21#include <syslog.h>
22#include <sys/klog.h>
23 22
24static void klogd_signal(int sig) 23
24/* The Linux-specific klogctl(3) interface does not rely on the filesystem and
25 * allows us to change the console loglevel. Alternatively, we read the
26 * messages from _PATH_KLOG. */
27
28#if ENABLE_FEATURE_KLOGD_KLOGCTL
29
30# include <sys/klog.h>
31
32static void klogd_open(void)
33{
34 /* "Open the log. Currently a NOP" */
35 klogctl(1, NULL, 0);
36}
37
38static void klogd_setloglevel(int lvl)
39{
40 /* "printk() prints a message on the console only if it has a loglevel
41 * less than console_loglevel". Here we set console_loglevel = lvl. */
42 klogctl(8, NULL, lvl);
43}
44
45static int klogd_read(char *bufp, int len)
46{
47 return klogctl(2, bufp, len);
48}
49# define READ_ERROR "klogctl(2) error"
50
51static void klogd_close(void)
25{ 52{
26 /* FYI: cmd 7 is equivalent to setting console_loglevel to 7 53 /* FYI: cmd 7 is equivalent to setting console_loglevel to 7
27 * via klogctl(8, NULL, 7). */ 54 * via klogctl(8, NULL, 7). */
28 klogctl(7, NULL, 0); /* "7 -- Enable printk's to console" */ 55 klogctl(7, NULL, 0); /* "7 -- Enable printk's to console" */
29 klogctl(0, NULL, 0); /* "0 -- Close the log. Currently a NOP" */ 56 klogctl(0, NULL, 0); /* "0 -- Close the log. Currently a NOP" */
30 syslog(LOG_NOTICE, "klogd: exiting");
31 kill_myself_with_sig(sig);
32} 57}
33 58
59#else
60
61# include <paths.h>
62# ifndef _PATH_KLOG
63# ifdef __GNU__
64# define _PATH_KLOG "/dev/klog"
65# else
66# error "your system's _PATH_KLOG is unknown"
67# endif
68# endif
69# define PATH_PRINTK "/proc/sys/kernel/printk"
70
71enum { klogfd = 3 };
72
73static void klogd_open(void)
74{
75 int fd = xopen(_PATH_KLOG, O_RDONLY);
76 xmove_fd(fd, klogfd);
77}
78
79static void klogd_setloglevel(int lvl)
80{
81 FILE *fp = fopen_or_warn(PATH_PRINTK, "w");
82 if (fp) {
83 /* This changes only first value:
84 * "messages with a higher priority than this
85 * [that is, with numerically lower value]
86 * will be printed to the console".
87 * The other three values in this pseudo-file aren't changed.
88 */
89 fprintf(fp, "%u\n", lvl);
90 fclose(fp);
91 }
92}
93
94static int klogd_read(char *bufp, int len)
95{
96 return read(klogfd, bufp, len);
97}
98# define READ_ERROR "read error"
99
100static void klogd_close(void)
101{
102 klogd_setloglevel(7);
103 if (ENABLE_FEATURE_CLEAN_UP)
104 close(klogfd);
105}
106
107#endif
108
34#define log_buffer bb_common_bufsiz1 109#define log_buffer bb_common_bufsiz1
35enum { 110enum {
36 KLOGD_LOGBUF_SIZE = sizeof(log_buffer), 111 KLOGD_LOGBUF_SIZE = sizeof(log_buffer),
@@ -38,6 +113,19 @@ enum {
38 OPT_FOREGROUND = (1 << 1), 113 OPT_FOREGROUND = (1 << 1),
39}; 114};
40 115
116/* TODO: glibc openlog(LOG_KERN) reverts to LOG_USER instead,
117 * because that's how they interpret word "default"
118 * in the openlog() manpage:
119 * LOG_USER (default)
120 * generic user-level messages
121 * and the fact that LOG_KERN is a constant 0.
122 * glibc interprets it as "0 in openlog() call means 'use default'".
123 * I think it means "if openlog wasn't called before syslog() is called,
124 * use default".
125 * Convincing glibc maintainers otherwise is, as usual, nearly impossible.
126 * Should we open-code syslog() here to use correct facility?
127 */
128
41int klogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 129int klogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
42int klogd_main(int argc UNUSED_PARAM, char **argv) 130int klogd_main(int argc UNUSED_PARAM, char **argv)
43{ 131{
@@ -55,34 +143,34 @@ int klogd_main(int argc UNUSED_PARAM, char **argv)
55 bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); 143 bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
56 } 144 }
57 145
58 openlog("kernel", 0, LOG_KERN); 146 logmode = LOGMODE_SYSLOG;
59
60 bb_signals(BB_FATAL_SIGS, klogd_signal);
61 signal(SIGHUP, SIG_IGN);
62 147
63 /* "Open the log. Currently a NOP" */ 148 /* klogd_open() before openlog(), since it might use fixed fd 3,
64 klogctl(1, NULL, 0); 149 * and openlog() also may use the same fd 3 if we swap them:
150 */
151 klogd_open();
152 openlog("kernel", 0, LOG_KERN);
65 153
66 /* "printk() prints a message on the console only if it has a loglevel
67 * less than console_loglevel". Here we set console_loglevel = i. */
68 if (i) 154 if (i)
69 klogctl(8, NULL, i); 155 klogd_setloglevel(i);
156
157 bb_signals(BB_FATAL_SIGS, record_signo);
158 signal(SIGHUP, SIG_IGN);
70 159
71 syslog(LOG_NOTICE, "klogd started: %s", bb_banner); 160 syslog(LOG_NOTICE, "klogd started: %s", bb_banner);
72 161
73 while (1) { 162 while (!bb_got_signal) {
74 int n; 163 int n;
75 int priority; 164 int priority;
76 char *start; 165 char *start;
77 166
78 /* "2 -- Read from the log." */ 167 /* "2 -- Read from the log." */
79 start = log_buffer + used; 168 start = log_buffer + used;
80 n = klogctl(2, start, KLOGD_LOGBUF_SIZE-1 - used); 169 n = klogd_read(start, KLOGD_LOGBUF_SIZE-1 - used);
81 if (n < 0) { 170 if (n < 0) {
82 if (errno == EINTR) 171 if (errno == EINTR)
83 continue; 172 continue;
84 syslog(LOG_ERR, "klogd: error %d in klogctl(2): %m", 173 bb_perror_msg(READ_ERROR);
85 errno);
86 break; 174 break;
87 } 175 }
88 start[n] = '\0'; 176 start[n] = '\0';
@@ -131,5 +219,9 @@ int klogd_main(int argc UNUSED_PARAM, char **argv)
131 } 219 }
132 } 220 }
133 221
222 klogd_close();
223 syslog(LOG_NOTICE, "klogd: exiting");
224 if (bb_got_signal)
225 kill_myself_with_sig(bb_got_signal);
134 return EXIT_FAILURE; 226 return EXIT_FAILURE;
135} 227}