syslogd 详解三

相关博文:

syslogd详解一

syslogd 详解二

 

前言

前两篇博文 syslogd详解一 和 syslogd 详解二 中详细解析了syslod的流程和实现原理,本篇将分析中syslog 中的另一部分——klogd。

 

先来看源码:

int klogd_main(int argc UNUSED_PARAM, char **argv)
{
    int i = 0;
    char *opt_c;
    int opt;
    int used;

    setup_common_bufsiz();

    opt = getopt32(argv, "c:n", &opt_c);
    if (opt & OPT_LEVEL) {
        /* Valid levels are between 1 and 8 */
        i = xatou_range(opt_c, 1, 8);
    }
    if (!(opt & OPT_FOREGROUND)) {
        bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
    }

    logmode = LOGMODE_SYSLOG;

    /* klogd_open() before openlog(), since it might use fixed fd 3,
     * and openlog() also may use the same fd 3 if we swap them:
     */
    klogd_open();
    openlog("kernel", 0, LOG_KERN);

    if (i)
        klogd_setloglevel(i);

    signal(SIGHUP, SIG_IGN);
    /* We want klogd_read to not be restarted, thus _norestart: */
    bb_signals_recursive_norestart(BB_FATAL_SIGS, record_signo);

    syslog(LOG_NOTICE, "klogd started: %s", bb_banner);

    write_pidfile(CONFIG_PID_FILE_PATH "/klogd.pid");

    used = 0;
    while (!bb_got_signal) {
        int n;
        int priority;
        char *start;

        /* "2 -- Read from the log." */
        start = log_buffer + used;
        n = klogd_read(start, KLOGD_LOGBUF_SIZE-1 - used);
        if (n < 0) {
            if (errno == EINTR)
                continue;
            bb_perror_msg(READ_ERROR);
            break;
        }
        start[n] = '\0';

        /* Process each newline-terminated line in the buffer */
        start = log_buffer;
        while (1) {
            char *newline = strchrnul(start, '\n');

            if (*newline == '\0') {
                /* This line is incomplete */

                /* move it to the front of the buffer */
                overlapping_strcpy(log_buffer, start);
                used = newline - start;
                if (used < KLOGD_LOGBUF_SIZE-1) {
                    /* buffer isn't full */
                    break;
                }
                /* buffer is full, log it anyway */
                used = 0;
                newline = NULL;
            } else {
                *newline++ = '\0';
            }

            /* Extract the priority */
            priority = LOG_INFO;
            if (*start == '<') {
                start++;
                if (*start)
                    priority = strtoul(start, &start, 10);
                if (*start == '>')
                    start++;
            }
            /* Log (only non-empty lines) */
            if (*start)
                syslog(priority, "%s", start);

            if (!newline)
                break;
            start = newline;
        }
    }

    klogd_close();
    syslog(LOG_NOTICE, "klogd: exiting");
    remove_pidfile(CONFIG_PID_FILE_PATH "/klogd.pid");
    if (bb_got_signal)
        kill_myself_with_sig(bb_got_signal);
    return EXIT_FAILURE;
}

从代码来看klogd 通过函数klogctl() 将内核的log 从ring buffer 中取出,然后再通过syslog 接口,在syslogd中通过/dev/log 存放。

这里核心的函数是klogctl():

#include 

extern int klogctl (int __type, char *__bufp, int __len);

 

这里用到klogctl 相关的函数有:

static void klogd_open(void)
{
    /* "Open the log. Currently a NOP" */
    klogctl(1, NULL, 0);
}

static void klogd_setloglevel(int lvl)
{
    /* "printk() prints a message on the console only if it has a loglevel
     * less than console_loglevel". Here we set console_loglevel = lvl. */
    klogctl(8, NULL, lvl);
}

static int klogd_read(char *bufp, int len)
{
    return klogctl(2, bufp, len);
}
# define READ_ERROR "klogctl(2) error"

static void klogd_close(void)
{
    /* FYI: cmd 7 is equivalent to setting console_loglevel to 7
     * via klogctl(8, NULL, 7). */
    klogctl(7, NULL, 0); /* "7 -- Enable printk's to console" */
    klogctl(0, NULL, 0); /* "0 -- Close the log. Currently a NOP" */
}

根据不同的type 实现不同的功能:

0        close log
1        open log
2        内核log 非空时,读取len大小的buffer到bufp中,已经读取的会从ring buffer中移除
3        读取所有内核log
4        读取所有内核log,并清空
5        清空内核log
6        关闭console,参数bufp和len被忽略
7        打开console,参数bufp和len被忽略
8        设置console的等级,1-8
9        返回内核log中可读的buffer 大小,参数bufp和len被忽略
10       内核log 的ring buffer 大小

 

命令行参数

klogd的命令行参数只有两个:

opt = getopt32(argv, "c:n", &opt_c);
-c       有选项参数,表示log 等级1-8
-n       无选项参数,表示前台运行

 

 

 

相关博文:

syslogd详解一

syslogd 详解二

 

参考:http://www.pianshen.com/article/3617573114/

你可能感兴趣的:(unix/linux)