syslogd: add option to log to Linux kernel printk buffer
authorPeter Korsgaard <jacmet@sunsite.dk>
Sat, 5 Jan 2013 23:07:19 +0000 (00:07 +0100)
committerMike Frysinger <vapier@gentoo.org>
Sun, 6 Jan 2013 18:30:50 +0000 (13:30 -0500)
Why invent our own shared memory circular buffer when the kernel has a
perfectly fine one already?

This can be used as a smaller/simpler alternative to the syslogd IPC support
(as IPC shmem/klogd/logread aren't needed), while also allowing centralised
logging of everything (kernel messages, userspace bootup and syslog)
when used together with ttyprintk.

Notice that kernel 3.5+ is needed to store syslog facility in printk buffer,
otherwise only the priority is stored.

bloat-o-meter compared to IPC+klogd+logread:
function                                             old     new   delta
get_linux_version_code                                 -      84     +84
lbb_prepare                                           25      90     +65
applet_nameofs                                         6       -      -6
static.stdout@@GLIBC_2                                 8       -      -8
applet_names                                          23       9     -14
bb_msg_standard_output                                16       -     -16
init_sem                                              18       -     -18
xatoull_range                                         19       -     -19
overlapping_strcpy                                    21       -     -21
init_data                                             56      32     -24
applet_main                                           24       -     -24
main                                                 124      99     -25
full_write2_str                                       26       -     -26
error_exit                                            26       -     -26
bb_basename                                           30       -     -30
sem_up                                                32       -     -32
interrupted                                           35       -     -35
fflush_stdout_and_exit                                38       -     -38
bb_banner                                             46       -     -46
find_applet_by_name                                   59       -     -59
bb_signals_recursive_norestart                        90       -     -90
run_applet_no_and_exit                               104       -    -104
timestamp_and_log                                    651     523    -128
syslogd_main                                         798     581    -217
xstrtoull_range_sfx                                  267       -    -267
run_applet_and_exit                                  432       -    -432
klogd_main                                           490       -    -490
logread_main                                         508       -    -508
.rodata                                             1870     937    -933
bb_common_bufsiz1                                   8193       -   -8193
------------------------------------------------------------------------------
(add/remove: 2/26 grow/shrink: 1/6 up/down: 149/-11829)    Total: -11680 bytes

Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
sysklogd/Config.src
sysklogd/syslogd.c

index b7a494eff07a89fcf2bbf98d8ccaf504ece05021..fcf993054f5661555ddb133a99485cb6b61fccea 100644 (file)
@@ -113,6 +113,19 @@ config FEATURE_LOGREAD_REDUCED_LOCKING
          from circular buffer, minimizing semaphore
          contention at some minor memory expense.
 
+config FEATURE_KMSG_SYSLOG
+       bool "Linux kernel printk buffer support"
+       default y
+       depends on SYSLOGD
+       select PLATFORM_LINUX
+       help
+         When you enable this feature, the syslogd utility will
+         write system log message to the Linux kernel's printk buffer.
+         This can be used as a smaller alternative to the syslogd IPC
+         support, as klogd and logread aren't needed.
+
+         NOTICE: Syslog facilities in log entries needs kernel 3.5+.
+
 config KLOGD
        bool "klogd"
        default y
@@ -123,6 +136,9 @@ config KLOGD
          you wish to record the messages produced by the kernel,
          you should enable this option.
 
+comment "klogd should not be used together with syslog to kernel printk buffer"
+       depends on KLOGD && FEATURE_KMSG_SYSLOG
+
 config FEATURE_KLOGD_KLOGCTL
        bool "Use the klogctl() interface"
        default y
index 5854bcd0f5f2f7e49be7d5f232bc295b4f000fcf..ad54e22ddbc84c7ee2fc90071dede4938662caf1 100644 (file)
@@ -43,6 +43,9 @@
 //usage:     "\n       -f FILE         Use FILE as config (default:/etc/syslog.conf)"
 //usage:       )
 /* //usage:  "\n       -m MIN          Minutes between MARK lines (default:20, 0=off)" */
+//usage:       IF_FEATURE_KMSG_SYSLOG(
+//usage:     "\n       -K              Log to kernel printk buffer (use dmesg to read it)"
+//usage:       )
 //usage:
 //usage:#define syslogd_example_usage
 //usage:       "$ syslogd -R masterlog:514\n"
@@ -140,6 +143,10 @@ IF_FEATURE_IPC_SYSLOG( \
 ) \
 IF_FEATURE_SYSLOGD_CFG( \
        logRule_t *log_rules; \
+) \
+IF_FEATURE_KMSG_SYSLOG( \
+       int kmsgfd; \
+       int primask; \
 )
 
 struct init_globals {
@@ -212,6 +219,7 @@ enum {
        IF_FEATURE_IPC_SYSLOG(    OPTBIT_circularlog,)  // -C
        IF_FEATURE_SYSLOGD_DUP(   OPTBIT_dup        ,)  // -D
        IF_FEATURE_SYSLOGD_CFG(   OPTBIT_cfg        ,)  // -f
+       IF_FEATURE_KMSG_SYSLOG(   OPTBIT_kmsg       ,)  // -K
 
        OPT_mark        = 1 << OPTBIT_mark    ,
        OPT_nofork      = 1 << OPTBIT_nofork  ,
@@ -225,6 +233,8 @@ enum {
        OPT_circularlog = IF_FEATURE_IPC_SYSLOG(    (1 << OPTBIT_circularlog)) + 0,
        OPT_dup         = IF_FEATURE_SYSLOGD_DUP(   (1 << OPTBIT_dup        )) + 0,
        OPT_cfg         = IF_FEATURE_SYSLOGD_CFG(   (1 << OPTBIT_cfg        )) + 0,
+       OPT_kmsg        = IF_FEATURE_KMSG_SYSLOG(   (1 << OPTBIT_kmsg       )) + 0,
+
 };
 #define OPTION_STR "m:nO:l:S" \
        IF_FEATURE_ROTATE_LOGFILE("s:" ) \
@@ -233,7 +243,8 @@ enum {
        IF_FEATURE_REMOTE_LOG(    "L"  ) \
        IF_FEATURE_IPC_SYSLOG(    "C::") \
        IF_FEATURE_SYSLOGD_DUP(   "D"  ) \
-       IF_FEATURE_SYSLOGD_CFG(   "f:"  )
+       IF_FEATURE_SYSLOGD_CFG(   "f:" ) \
+       IF_FEATURE_KMSG_SYSLOG(   "K"  )
 #define OPTION_DECL *opt_m, *opt_l \
        IF_FEATURE_ROTATE_LOGFILE(,*opt_s) \
        IF_FEATURE_ROTATE_LOGFILE(,*opt_b) \
@@ -523,6 +534,44 @@ void ipcsyslog_init(void);
 void log_to_shmem(const char *msg);
 #endif /* FEATURE_IPC_SYSLOG */
 
+#if ENABLE_FEATURE_KMSG_SYSLOG
+static void kmsg_init(void)
+{
+       G.kmsgfd = xopen("/dev/kmsg", O_WRONLY);
+
+       /*
+        * kernel < 3.5 expects single char printk KERN_* priority prefix,
+        * from 3.5 onwards the full syslog facility/priority format is supported
+        */
+       if (get_linux_version_code() < KERNEL_VERSION(3,5,0))
+               G.primask = LOG_PRIMASK;
+       else
+               G.primask = -1;
+}
+
+static void kmsg_cleanup(void)
+{
+       if (ENABLE_FEATURE_CLEAN_UP)
+               close(G.kmsgfd);
+}
+
+/* Write message to /dev/kmsg */
+static void log_to_kmsg(int pri, const char *msg)
+{
+       /*
+        * kernel < 3.5 expects single char printk KERN_* priority prefix,
+        * from 3.5 onwards the full syslog facility/priority format is supported
+        */
+       pri &= G.primask;
+
+       write(G.kmsgfd, G.printbuf, sprintf(G.printbuf, "<%d>%s\n", pri, msg));
+}
+#else
+void kmsg_init(void);
+void kmsg_cleanup(void);
+void log_to_kmsg(int pri, const char *msg);
+#endif /* FEATURE_KMSG_SYSLOG */
+
 /* Print a message to the log file. */
 static void log_locally(time_t now, char *msg, logFile_t *log_file)
 {
@@ -657,6 +706,11 @@ static void timestamp_and_log(int pri, char *msg, int len)
        }
        timestamp[15] = '\0';
 
+       if (ENABLE_FEATURE_KMSG_SYSLOG && (option_mask32 & OPT_kmsg)) {
+               log_to_kmsg(pri, msg);
+               return;
+       }
+
        if (option_mask32 & OPT_small)
                sprintf(G.printbuf, "%s %s\n", timestamp, msg);
        else {
@@ -831,6 +885,9 @@ static void do_syslogd(void)
                ipcsyslog_init();
        }
 
+       if (ENABLE_FEATURE_KMSG_SYSLOG && (option_mask32 & OPT_kmsg))
+               kmsg_init();
+
        timestamp_and_log_internal("syslogd started: BusyBox v" BB_VER);
 
        while (!bb_got_signal) {
@@ -919,6 +976,8 @@ static void do_syslogd(void)
        remove_pidfile(CONFIG_PID_FILE_PATH "/syslogd.pid");
        if (ENABLE_FEATURE_IPC_SYSLOG)
                ipcsyslog_cleanup();
+       if (ENABLE_FEATURE_KMSG_SYSLOG && (option_mask32 & OPT_kmsg))
+               kmsg_cleanup();
        kill_myself_with_sig(bb_got_signal);
 #undef recvbuf
 }