c4bbf1558b57a88703fe015c00d48f1a85080907
[oweals/busybox.git] / sysklogd / klogd.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini klogd implementation for busybox
4  *
5  * Copyright (C) 2001 by Gennady Feldman <gfeldman@gena01.com>.
6  * Changes: Made this a standalone busybox module which uses standalone
7  *                                      syslog() client interface.
8  *
9  * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
10  *
11  * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org>
12  *
13  * "circular buffer" Copyright (C) 2000 by Gennady Feldman <gfeldman@gena01.com>
14  *
15  * Maintainer: Gennady Feldman <gfeldman@gena01.com> as of Mar 12, 2001
16  *
17  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
18  */
19
20 #include "libbb.h"
21 #include <syslog.h>
22 #include <sys/klog.h>
23
24 static void klogd_signal(int sig)
25 {
26         /* FYI: cmd 7 is equivalent to setting console_loglevel to 7
27          * via klogctl(8, NULL, 7). */
28         klogctl(7, NULL, 0); /* "7 -- Enable printk's to console" */
29         klogctl(0, NULL, 0); /* "0 -- Close the log. Currently a NOP" */
30         syslog(LOG_NOTICE, "klogd: exiting");
31         kill_myself_with_sig(sig);
32 }
33
34 #define log_buffer bb_common_bufsiz1
35 enum {
36         KLOGD_LOGBUF_SIZE = sizeof(log_buffer),
37         OPT_LEVEL      = (1 << 0),
38         OPT_FOREGROUND = (1 << 1),
39 };
40
41 int klogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
42 int klogd_main(int argc UNUSED_PARAM, char **argv)
43 {
44         int i = 0;
45         char *start;
46         int opt;
47
48         opt = getopt32(argv, "c:n", &start);
49         if (opt & OPT_LEVEL) {
50                 /* Valid levels are between 1 and 8 */
51                 i = xatou_range(start, 1, 8);
52         }
53         if (!(opt & OPT_FOREGROUND)) {
54                 bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
55         }
56
57         openlog("kernel", 0, LOG_KERN);
58
59         bb_signals(0
60                 + (1 << SIGINT)
61                 + (1 << SIGTERM)
62                 , klogd_signal);
63         signal(SIGHUP, SIG_IGN);
64
65         /* "Open the log. Currently a NOP" */
66         klogctl(1, NULL, 0);
67
68         /* "printk() prints a message on the console only if it has a loglevel
69          * less than console_loglevel". Here we set console_loglevel = i. */
70         if (i)
71                 klogctl(8, NULL, i);
72
73         syslog(LOG_NOTICE, "klogd started: %s", bb_banner);
74
75         /* Note: this code does not detect incomplete messages
76          * (messages not ending with '\n' or just when kernel
77          * generates too many messages for us to keep up)
78          * and will split them in two separate lines */
79         while (1) {
80                 int n;
81                 int priority;
82
83                 /* "2 -- Read from the log." */
84                 n = klogctl(2, log_buffer, KLOGD_LOGBUF_SIZE - 1);
85                 if (n < 0) {
86                         if (errno == EINTR)
87                                 continue;
88                         syslog(LOG_ERR, "klogd: error %d in klogctl(2): %m",
89                                         errno);
90                         break;
91                 }
92                 log_buffer[n] = '\n';
93                 i = 0;
94                 while (i < n) {
95                         priority = LOG_INFO;
96                         start = &log_buffer[i];
97                         if (log_buffer[i] == '<') {
98                                 i++;
99                                 // kernel never ganerates multi-digit prios
100                                 //priority = 0;
101                                 //while (log_buffer[i] >= '0' && log_buffer[i] <= '9') {
102                                 //      priority = priority * 10 + (log_buffer[i] - '0');
103                                 //      i++;
104                                 //}
105                                 if (isdigit(log_buffer[i])) {
106                                         priority = (log_buffer[i] - '0');
107                                         i++;
108                                 }
109                                 if (log_buffer[i] == '>')
110                                         i++;
111                                 start = &log_buffer[i];
112                         }
113                         while (log_buffer[i] != '\n')
114                                 i++;
115                         log_buffer[i] = '\0';
116                         syslog(priority, "%s", start);
117                         i++;
118                 }
119         }
120
121         return EXIT_FAILURE;
122 }