diff options
Diffstat (limited to 'sysklogd')
-rw-r--r-- | sysklogd/Config.src | 17 | ||||
-rw-r--r-- | sysklogd/klogd.c | 128 | ||||
-rw-r--r-- | sysklogd/syslogd.c | 26 |
3 files changed, 146 insertions, 25 deletions
diff --git a/sysklogd/Config.src b/sysklogd/Config.src index 6d574abb1..1e5987275 100644 --- a/sysklogd/Config.src +++ b/sysklogd/Config.src | |||
@@ -116,6 +116,22 @@ config KLOGD | |||
116 | you wish to record the messages produced by the kernel, | 116 | you wish to record the messages produced by the kernel, |
117 | you should enable this option. | 117 | you should enable this option. |
118 | 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 | |||
119 | config LOGGER | 135 | config LOGGER |
120 | bool "logger" | 136 | bool "logger" |
121 | default y | 137 | default y |
@@ -127,4 +143,3 @@ config LOGGER | |||
127 | problems that occur within programs and scripts. | 143 | problems that occur within programs and scripts. |
128 | 144 | ||
129 | endmenu | 145 | endmenu |
130 | |||
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 | } |
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c index 6bc450bf9..37a119b3d 100644 --- a/sysklogd/syslogd.c +++ b/sysklogd/syslogd.c | |||
@@ -546,7 +546,7 @@ static int try_to_resolve_remote(remoteHost_t *rh) | |||
546 | if (!rh->remoteAddr) | 546 | if (!rh->remoteAddr) |
547 | return -1; | 547 | return -1; |
548 | } | 548 | } |
549 | return socket(rh->remoteAddr->u.sa.sa_family, SOCK_DGRAM, 0); | 549 | return xsocket(rh->remoteAddr->u.sa.sa_family, SOCK_DGRAM, 0); |
550 | } | 550 | } |
551 | #endif | 551 | #endif |
552 | 552 | ||
@@ -636,11 +636,25 @@ static void do_syslogd(void) | |||
636 | if (rh->remoteFD == -1) | 636 | if (rh->remoteFD == -1) |
637 | continue; | 637 | continue; |
638 | } | 638 | } |
639 | /* Send message to remote logger, ignore possible error */ | 639 | |
640 | /* TODO: on some errors, close and set G.remoteFD to -1 | 640 | /* Send message to remote logger. |
641 | * so that DNS resolution and connect is retried? */ | 641 | * On some errors, close and set remoteFD to -1 |
642 | sendto(rh->remoteFD, recvbuf, sz+1, MSG_DONTWAIT, | 642 | * so that DNS resolution is retried. |
643 | &(rh->remoteAddr->u.sa), rh->remoteAddr->len); | 643 | */ |
644 | if (sendto(rh->remoteFD, recvbuf, sz+1, | ||
645 | MSG_DONTWAIT | MSG_NOSIGNAL, | ||
646 | &(rh->remoteAddr->u.sa), rh->remoteAddr->len) == -1 | ||
647 | ) { | ||
648 | switch (errno) { | ||
649 | case ECONNRESET: | ||
650 | case ENOTCONN: /* paranoia */ | ||
651 | case EPIPE: | ||
652 | close(rh->remoteFD); | ||
653 | rh->remoteFD = -1; | ||
654 | free(rh->remoteAddr); | ||
655 | rh->remoteAddr = NULL; | ||
656 | } | ||
657 | } | ||
644 | } | 658 | } |
645 | #endif | 659 | #endif |
646 | if (!ENABLE_FEATURE_REMOTE_LOG || (option_mask32 & OPT_locallog)) { | 660 | if (!ENABLE_FEATURE_REMOTE_LOG || (option_mask32 & OPT_locallog)) { |