tizen 2.3.1 release
[external/busybox.git] / packaging / klogd-make-it-work-on-non-linux-systems.patch
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
5
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.
9
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
12
13 Signed-off-by: Jeremie Koenig <jk@jk.fr.eu.org>
14 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
15 ---
16  sysklogd/Config.src |   17 ++++++-
17  sysklogd/klogd.c    |  128 +++++++++++++++++++++++++++++++++++++++++++-------
18  2 files changed, 126 insertions(+), 19 deletions(-)
19
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
25  config KLOGD
26         bool "klogd"
27         default y
28 -       depends on PLATFORM_LINUX
29         help
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.
35  
36 +config FEATURE_KLOGD_KLOGCTL
37 +       bool "Use the klogctl() interface"
38 +       default y
39 +       depends on KLOGD && PLATFORM_LINUX
40 +       help
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.
45 +
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.
49 +
50 +         If in doubt, say 'Y'.
51 +
52  config LOGGER
53         bool "logger"
54         default 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
59 @@ -4,7 +4,7 @@
60   *
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.
65   *
66   * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
67   *
68 @@ -19,18 +19,93 @@
69  
70  #include "libbb.h"
71  #include <syslog.h>
72 -#include <sys/klog.h>
73  
74 -static void klogd_signal(int sig)
75 +
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. */
79 +
80 +#if ENABLE_FEATURE_KLOGD_KLOGCTL
81 +
82 +# include <sys/klog.h>
83 +
84 +static void klogd_open(void)
85 +{
86 +       /* "Open the log. Currently a NOP" */
87 +       klogctl(1, NULL, 0);
88 +}
89 +
90 +static void klogd_setloglevel(int lvl)
91 +{
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);
95 +}
96 +
97 +static int klogd_read(char *bufp, int len)
98 +{
99 +       return klogctl(2, bufp, len);
100 +}
101 +# define READ_ERROR "klogctl(2) error"
102 +
103 +static void klogd_close(void)
104  {
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);
111  }
112  
113 +#else
114 +
115 +# include <paths.h>
116 +# ifndef _PATH_KLOG
117 +#  ifdef __GNU__
118 +#   define _PATH_KLOG "/dev/klog"
119 +#  else
120 +#   error "your system's _PATH_KLOG is unknown"
121 +#  endif
122 +# endif
123 +# define PATH_PRINTK "/proc/sys/kernel/printk"
124 +
125 +enum { klogfd = 3 };
126 +
127 +static void klogd_open(void)
128 +{
129 +       int fd = xopen(_PATH_KLOG, O_RDONLY);
130 +       xmove_fd(fd, klogfd);
131 +}
132 +
133 +static void klogd_setloglevel(int lvl)
134 +{
135 +       FILE *fp = fopen_or_warn(PATH_PRINTK, "w");
136 +       if (fp) {
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.
142 +                */
143 +               fprintf(fp, "%u\n", lvl);
144 +               fclose(fp);
145 +       }
146 +}
147 +
148 +static int klogd_read(char *bufp, int len)
149 +{
150 +       return read(klogfd, bufp, len);
151 +}
152 +# define READ_ERROR "read error"
153 +
154 +static void klogd_close(void)
155 +{
156 +       klogd_setloglevel(7);
157 +       if (ENABLE_FEATURE_CLEAN_UP)
158 +               close(klogfd);
159 +}
160 +
161 +#endif
162 +
163  #define log_buffer bb_common_bufsiz1
164  enum {
165         KLOGD_LOGBUF_SIZE = sizeof(log_buffer),
166 @@ -38,6 +113,19 @@ enum {
167         OPT_FOREGROUND = (1 << 1),
168  };
169  
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,
178 + * use default".
179 + * Convincing glibc maintainers otherwise is, as usual, nearly impossible.
180 + * Should we open-code syslog() here to use correct facility?
181 + */
182 +
183  int klogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
184  int klogd_main(int argc UNUSED_PARAM, char **argv)
185  {
186 @@ -55,34 +143,34 @@ int klogd_main(int argc UNUSED_PARAM, char **argv)
187                 bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
188         }
189  
190 -       openlog("kernel", 0, LOG_KERN);
191 -
192 -       bb_signals(BB_FATAL_SIGS, klogd_signal);
193 -       signal(SIGHUP, SIG_IGN);
194 +       logmode = LOGMODE_SYSLOG;
195  
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:
200 +        */
201 +       klogd_open();
202 +       openlog("kernel", 0, LOG_KERN);
203  
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. */
206         if (i)
207 -               klogctl(8, NULL, i);
208 +               klogd_setloglevel(i);
209 +
210 +       bb_signals(BB_FATAL_SIGS, record_signo);
211 +       signal(SIGHUP, SIG_IGN);
212  
213         syslog(LOG_NOTICE, "klogd started: %s", bb_banner);
214  
215 -       while (1) {
216 +       while (!bb_got_signal) {
217                 int n;
218                 int priority;
219                 char *start;
220  
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);
225                 if (n < 0) {
226                         if (errno == EINTR)
227                                 continue;
228 -                       syslog(LOG_ERR, "klogd: error %d in klogctl(2): %m",
229 -                                       errno);
230 +                       bb_perror_msg(READ_ERROR);
231                         break;
232                 }
233                 start[n] = '\0';
234 @@ -131,5 +219,9 @@ int klogd_main(int argc UNUSED_PARAM, char **argv)
235                 }
236         }
237  
238 +       klogd_close();
239 +       syslog(LOG_NOTICE, "klogd: exiting");
240 +       if (bb_got_signal)
241 +               kill_myself_with_sig(bb_got_signal);
242         return EXIT_FAILURE;
243  }
244 -- 
245 1.7.1
246