Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/sysklogd/klogd.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/sysklogd/klogd.c
r1765 r2725 5 5 * Copyright (C) 2001 by Gennady Feldman <gfeldman@gena01.com>. 6 6 * Changes: Made this a standalone busybox module which uses standalone 7 * 7 * syslog() client interface. 8 8 * 9 9 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> … … 15 15 * Maintainer: Gennady Feldman <gfeldman@gena01.com> as of Mar 12, 2001 16 16 * 17 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.17 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 18 18 */ 19 19 20 20 #include "libbb.h" 21 #include <sys/syslog.h> 22 #include <sys/klog.h> 23 24 static void klogd_signal(int sig ATTRIBUTE_UNUSED) 25 { 26 klogctl(7, NULL, 0); 27 klogctl(0, 0, 0); 28 syslog(LOG_NOTICE, "Kernel log daemon exiting"); 29 exit(EXIT_SUCCESS); 30 } 31 32 #define OPT_LEVEL 1 33 #define OPT_FOREGROUND 2 34 35 #define KLOGD_LOGBUF_SIZE BUFSIZ 21 #include <syslog.h> 22 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) 52 { 53 /* FYI: cmd 7 is equivalent to setting console_loglevel to 7 54 * via klogctl(8, NULL, 7). */ 55 klogctl(7, NULL, 0); /* "7 -- Enable printk's to console" */ 56 klogctl(0, NULL, 0); /* "0 -- Close the log. Currently a NOP" */ 57 } 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 36 109 #define log_buffer bb_common_bufsiz1 37 38 int klogd_main(int argc, char **argv); 39 int klogd_main(int argc, char **argv) 40 { 41 int i = i; /* silence gcc */ 42 char *start; 43 44 /* do normal option parsing */ 45 getopt32(argv, "c:n", &start); 46 47 if (option_mask32 & OPT_LEVEL) { 110 enum { 111 KLOGD_LOGBUF_SIZE = sizeof(log_buffer), 112 OPT_LEVEL = (1 << 0), 113 OPT_FOREGROUND = (1 << 1), 114 }; 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 129 int klogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 130 int klogd_main(int argc UNUSED_PARAM, char **argv) 131 { 132 int i = 0; 133 char *opt_c; 134 int opt; 135 int used; 136 137 opt = getopt32(argv, "c:n", &opt_c); 138 if (opt & OPT_LEVEL) { 48 139 /* Valid levels are between 1 and 8 */ 49 i = xatoul_range(start, 1, 8); 50 } 51 52 if (!(option_mask32 & OPT_FOREGROUND)) { 140 i = xatou_range(opt_c, 1, 8); 141 } 142 if (!(opt & OPT_FOREGROUND)) { 53 143 bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); 54 144 } 55 145 146 logmode = LOGMODE_SYSLOG; 147 148 /* klogd_open() before openlog(), since it might use fixed fd 3, 149 * and openlog() also may use the same fd 3 if we swap them: 150 */ 151 klogd_open(); 56 152 openlog("kernel", 0, LOG_KERN); 57 153 58 /* Set up sig handlers */59 signal(SIGINT, klogd_signal);60 signal(SIGKILL, klogd_signal); 61 signal(SIGTERM, klogd_signal);154 if (i) 155 klogd_setloglevel(i); 156 157 bb_signals(BB_FATAL_SIGS, record_signo); 62 158 signal(SIGHUP, SIG_IGN); 63 159 64 /* "Open the log. Currently a NOP." */65 klogctl(1, NULL, 0);66 67 /* Set level of kernel console messaging. */68 if (option_mask32 & OPT_LEVEL)69 klogctl(8, NULL, i);70 71 160 syslog(LOG_NOTICE, "klogd started: %s", bb_banner); 72 161 73 /* Note: this code does not detect incomplete messages 74 * (messages not ending with '\n' or just when kernel 75 * generates too many messages for us to keep up) 76 * and will split them in two separate lines */ 77 while (1) { 162 used = 0; 163 while (!bb_got_signal) { 78 164 int n; 79 165 int priority; 80 81 n = klogctl(2, log_buffer, KLOGD_LOGBUF_SIZE - 1); 166 char *start; 167 168 /* "2 -- Read from the log." */ 169 start = log_buffer + used; 170 n = klogd_read(start, KLOGD_LOGBUF_SIZE-1 - used); 82 171 if (n < 0) { 83 172 if (errno == EINTR) 84 173 continue; 85 syslog(LOG_ERR, "klogd: error from klogctl(2): %d - %m", 86 errno); 174 bb_perror_msg(READ_ERROR); 87 175 break; 88 176 } 89 log_buffer[n] = '\n'; 90 i = 0; 91 while (i < n) { 177 start[n] = '\0'; 178 179 /* Process each newline-terminated line in the buffer */ 180 start = log_buffer; 181 while (1) { 182 char *newline = strchrnul(start, '\n'); 183 184 if (*newline == '\0') { 185 /* This line is incomplete */ 186 187 /* move it to the front of the buffer */ 188 overlapping_strcpy(log_buffer, start); 189 used = newline - start; 190 if (used < KLOGD_LOGBUF_SIZE-1) { 191 /* buffer isn't full */ 192 break; 193 } 194 /* buffer is full, log it anyway */ 195 used = 0; 196 newline = NULL; 197 } else { 198 *newline++ = '\0'; 199 } 200 201 /* Extract the priority */ 92 202 priority = LOG_INFO; 93 start = &log_buffer[i]; 94 if (log_buffer[i] == '<') { 95 i++; 96 // kernel never ganerates multi-digit prios 97 //priority = 0; 98 //while (log_buffer[i] >= '0' && log_buffer[i] <= '9') { 99 // priority = priority * 10 + (log_buffer[i] - '0'); 100 // i++; 101 //} 102 if (isdigit(log_buffer[i])) { 103 priority = (log_buffer[i] - '0'); 104 i++; 203 if (*start == '<') { 204 start++; 205 if (*start) { 206 /* kernel never generates multi-digit prios */ 207 priority = (*start - '0'); 208 start++; 105 209 } 106 if (log_buffer[i] == '>') 107 i++; 108 start = &log_buffer[i]; 210 if (*start == '>') 211 start++; 109 212 } 110 while (log_buffer[i] != '\n') 111 i++; 112 log_buffer[i] = '\0'; 113 syslog(priority, "%s", start); 114 i++; 213 /* Log (only non-empty lines) */ 214 if (*start) 215 syslog(priority, "%s", start); 216 217 if (!newline) 218 break; 219 start = newline; 115 220 } 116 221 } 117 222 223 klogd_close(); 224 syslog(LOG_NOTICE, "klogd: exiting"); 225 if (bb_got_signal) 226 kill_myself_with_sig(bb_got_signal); 118 227 return EXIT_FAILURE; 119 228 }
Note:
See TracChangeset
for help on using the changeset viewer.