diff options
author | Jeremie Koenig <jk@jk.fr.eu.org> | 2010-08-01 03:01:44 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-08-01 03:01:44 +0200 |
commit | 63c2e7ecc0c7a72b2ed35475a8d18d3052039ce4 (patch) | |
tree | 502795272936f6225a3ae268d40dfbf80027c89f | |
parent | 17662801ece60bbcc45bbc3cb1fc0fc3070d0d23 (diff) | |
download | busybox-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.src | 17 | ||||
-rw-r--r-- | sysklogd/klogd.c | 128 |
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 | |||
109 | config KLOGD | 109 | config 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 | ||
119 | config 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 | |||
120 | config LOGGER | 135 | config 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 | ||
24 | static 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 | |||
32 | static void klogd_open(void) | ||
33 | { | ||
34 | /* "Open the log. Currently a NOP" */ | ||
35 | klogctl(1, NULL, 0); | ||
36 | } | ||
37 | |||
38 | static 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 | |||
45 | static int klogd_read(char *bufp, int len) | ||
46 | { | ||
47 | return klogctl(2, bufp, len); | ||
48 | } | ||
49 | # define READ_ERROR "klogctl(2) error" | ||
50 | |||
51 | static 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 | |||
71 | enum { klogfd = 3 }; | ||
72 | |||
73 | static void klogd_open(void) | ||
74 | { | ||
75 | int fd = xopen(_PATH_KLOG, O_RDONLY); | ||
76 | xmove_fd(fd, klogfd); | ||
77 | } | ||
78 | |||
79 | static 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 | |||
94 | static int klogd_read(char *bufp, int len) | ||
95 | { | ||
96 | return read(klogfd, bufp, len); | ||
97 | } | ||
98 | # define READ_ERROR "read error" | ||
99 | |||
100 | static 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 |
35 | enum { | 110 | enum { |
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 | |||
41 | int klogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 129 | int klogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
42 | int klogd_main(int argc UNUSED_PARAM, char **argv) | 130 | int 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 | } |