/*
 *  linux/kernel/printk.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *
 * Modified to make sys_syslog() more flexible: added commands to
 * return the last 4k of kernel messages, regardless of whether
 * they've been read or not.  Added option to suppress kernel printk's
 * to the console.  Added hook for sending the console messages
 * elsewhere, in preparation for a serial line console (someday).
 * Ted Ts'o, 2/11/93.
 */

#include <stdarg.h>

#include <asm/segment.h>
#include <asm/system.h>

#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>

#define LOG_BUF_LEN    4096

static char buf[1024];

extern int vsprintf(char * buf, const char * fmt, va_list args);
extern void console_print(const char *);

#define DEFAULT_MESSAGE_LOGLEVEL 7 /* KERN_DEBUG */
#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything more serious than KERN_DEBUG */

unsigned long log_size = 0;
struct wait_queue * log_wait = NULL;
int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;

static void (*console_print_proc)(const char *) = 0;
static char log_buf[LOG_BUF_LEN];
static unsigned long log_start = 0;
static unsigned long logged_chars = 0;

/*
 * Commands to sys_syslog:
 *
 *     0 -- Close the log.  Currently a NOP.                             关闭日志,当前不处理
 *     1 -- Open the log. Currently a NOP.                               打开日中
 *     2 -- Read from the log.                                           从日志中读取
 *     3 -- Read up to the last 4k of messages in the ring buffer.       在环形缓冲区中读取最近的4K消息
 *     4 -- Read and clear last 4k of messages in the ring buffer        在环形缓冲区中读取并清空最近的4K消息
 *     5 -- Clear ring buffer.                                           清空环形缓冲区
 *     6 -- Disable printk's to console                                  禁制输出消息到控制台
 *     7 -- Enable printk's to console                                   使消息输出到控制台
 *    8 -- Set level of messages printed to console                     设置消息的级别
 */
 //系统日志
asmlinkage int sys_syslog(int type, char * buf, int len)
{
    unsigned long i, j, count;
    int do_clear = 0;
    char c;
    int error;
    //权限检测
    if ((type != 3) && !suser())
        return -EPERM;
    switch (type) {
        case 0:        /* Close log */
            return 0;
        case 1:        /* Open log */
            return 0;
        case 2:        /* Read from log */
            if (!buf || len < 0)
                return -EINVAL;
            if (!len)
                return 0;
            //对指定位置进行写权限验证
            error = verify_area(VERIFY_WRITE,buf,len);
            if (error)
                return error;
            cli();
            //
            while (!log_size) {
                if (current->signal & ~current->blocked) {
                    sti();
                    return -ERESTARTSYS;
                }
                interruptible_sleep_on(&log_wait);
            }
            i = 0;
            while (log_size && i < len) {
                //计算位置
                c = *((char *) log_buf+log_start);
                log_start++;
                log_size--;
                log_start &= LOG_BUF_LEN-1;
                //开中断
                sti();
                //写入缓冲区
                put_fs_byte(c,buf);
                buf++;
                i++;
                //关中断
                cli();
            }
            sti();
            return i;
        case 4:        /* Read/clear last kernel messages */
            do_clear = 1;
            /* FALL THRU */
        case 3:        /* Read last kernel messages */
            if (!buf || len < 0)//校验后读取数据,并清空
                return -EINVAL;
            if (!len)
                return 0;
            error = verify_area(VERIFY_WRITE,buf,len);
            if (error)
                return error;
            count = len;
            if (count > LOG_BUF_LEN)
                count = LOG_BUF_LEN;
            if (count > logged_chars)
                count = logged_chars;
            j = log_start + log_size - count;
            for (i = 0; i < count; i++) {
                c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
                put_fs_byte(c, buf++);
            }
            if (do_clear)
                logged_chars = 0;
            return i;
        case 5:        /* Clear ring buffer */
            logged_chars = 0;
            return 0;
        case 6:        /* Disable logging to console */
            console_loglevel = 1; /* only panic messages shown */
            return 0;
        case 7:        /* Enable logging to console */
            console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
            return 0;
        case 8:
            if (len < 0 || len > 8)
                return -EINVAL;
            console_loglevel = len;
            return 0;
    }
    return -EINVAL;
}

//输出
asmlinkage int printk(const char *fmt, ...)
{
    va_list args;
    int i;
    char *msg, *p, *buf_end;
    static char msg_level = -1;
    long flags;

save_flags(flags);
    cli();
    va_start(args, fmt);
    i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */
    buf_end = buf + 3 + i;
    va_end(args);
    for (p = buf + 3; p < buf_end; p++) {
        msg = p;
        //确定日志级别
        if (msg_level < 0) {
            if (
                p[0] != '<' ||
                p[1] < '0' ||
                p[1] > '7' ||
                p[2] != '>'
            ) {
                p -= 3;
                p[0] = '<';
                p[1] = DEFAULT_MESSAGE_LOGLEVEL - 1 + '0';
                p[2] = '>';
            } else
                msg += 3;
            msg_level = p[1] - '0';
        }
        //循环拷贝日志内容
        for (; p < buf_end; p++) {
            log_buf[(log_start+log_size) & (LOG_BUF_LEN-1)] = *p;
            if (log_size < LOG_BUF_LEN)
                log_size++;
            else
                log_start++;
            logged_chars++;
            if (*p == '\n')
                break;
        }
        //输出到控制台
        if (msg_level < console_loglevel && console_print_proc) {
            char tmp = p[1];
            p[1] = '\0';
            (*console_print_proc)(msg);
            p[1] = tmp;
        }
        if (*p == '\n')
            msg_level = -1;
    }
    restore_flags(flags);
    wake_up_interruptible(&log_wait);
    return i;
}

/*
 * The console driver calls this routine during kernel initialization
 * to register the console printing procedure with printk() and to
 * print any messages that were printed by the kernel before the
 * console driver was initialized.
 */
 //注册控制台输出,参数为函数指针
void register_console(void (*proc)(const char *))
{
    int    i,j;
    int    p = log_start;
    char    buf[16];
    char    msg_level = -1;
    char    *q;
    //挂接回调函数
    console_print_proc = proc;

//
    for (i=0,j=0; i < log_size; i++) {
        buf[j++] = log_buf[p];
        p++; p &= LOG_BUF_LEN-1;
        if (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)-1)
            continue;
        buf[j] = 0;
        q = buf;
        if (msg_level < 0) {
            msg_level = buf[1] - '0';
            q = buf + 3;
        }
        if (msg_level < console_loglevel)
            (*proc)(q);
        if (buf[j-1] == '\n')
            msg_level = -1;
        j = 0;
    }
}

kernel/printk.c的更多相关文章

  1. kernel printk信息显示级别

    涉及文件:kernel/printk.c include/linux/kernel.h用printk内核会根据日志级别把消息打印到当前控制台上.信息正常输出前提是--日志输出级别(msg_log_le ...

  2. [kernel]内核日志及printk结构分析

    一直都知道内核printk分级机制,但是没有去了解过,前段时间和一个同事聊到开机启动打印太多,只需要设置一下等级即可:另外今天看驱动源码,也看到类似于Printk(KERN_ERR "... ...

  3. linux内核调试技术之printk

    原创博客:欢迎转载,转载请注明出处https://i.cnblogs.com/EditPosts.aspx?postid=6218383 1.简介(基于s3c2440 linux) 在内核调试技术之中 ...

  4. linux内核打印数据到串口控制台,printk数据不打印问题

    linux内核打印数据到串口控制台问题 原文来源:http://i.cnblogs.com/EditPosts.aspx?opt=1 1.查看当前控制台的打印级别 cat /proc/sys/kern ...

  5. linux驱动中printk的使用注意事项

    今天在按键驱动中增加printk(KERN_INFO "gpio_keys_gpio_isr()\n");在驱动加载阶段可以输出调试信息,但驱动加载起来后的信息,在串口端看不到输出 ...

  6. [linux-内核][转]内核日志及printk结构浅析

    这段时间复习了一下内核调试系统,注意看了一下printk的实现以及内核日志的相关知识,这里做一下总结. 1.问题的引出: 做DPDK项目时,调试rte_kni.ko时,发现printk并不会向我们想想 ...

  7. linux中模块的构建,传参,和printk函数的简单使用

    静态编译,动态加载应用想访问内核需要通过系统调用 驱动:1.模块(打包,加入内核)2.内核机制3.操作硬件 在Kconfig里面配置menuconfig的时候,不同的类型会在图形化界面的终端显示不用的 ...

  8. printk函数日志级别的设置【转】

    本文转载自: 下面执行cat /proc/sys/kernel/printk 打印出的四个数字分别代表: 控制台日志级别.默认的消息日志级别.最低的控制台日志级别和默认的控制台日志级别 只有当prin ...

  9. 更改printk打印级别

    1.查看当前控制台的打印级别 cat /proc/sys/kernel/printk 4    4    1    7 其中第一个"4"表示内核打印函数printk的打印级别,只有 ...

随机推荐

  1. 7个步骤:让JavaScript变得更好

    Dan Odell介绍了他编写的七步写出无瑕代码的计划,是在简化过程中最有用的工具.   随着浏览器性能提高,伴随着新的HTML5的编程接口的稳步采用,网页上的JavaScript的音量在逐渐增加.然 ...

  2. Microsoft Azure Project Oxford 体验

    2015年4月29日,微软在Build 2015大会上发布了一个震撼人心的项目: Project Oxford, 可以帮助直接实现图像理解.人脸识别.语音识别.语音合成等功能.虽然说这是号称研究院的项 ...

  3. While循环

    package ForType; public class ForType { /** * @param args */ public static void main(String[] args) ...

  4. MFC-01-Chapter01:Hello,MFC---1.3 第一个MFC程序(01)

    #include <afxwin.h> class CMyApp : public CWinApp { public: virtual BOOL InitInstance(); }; cl ...

  5. 对于.NET Socket连接的细节记录

    如果客户端直接连接一个不存在的服务器端,客户端会抛出异常: 如果在连接过程中,客户端强制关闭了连接(没有调用Close直接关闭了程序),服务器端会抛出异常: 如果在连接过程中,客户端调用了Close, ...

  6. asp.net文件下载文件另存为

    这是一个困惑已久的问题…… 首先,用<a>标签的href打开浏览器能解读的文件(如txt,jpg,pdf等),会自动打开,无法做到弹出另存为的效果. 其次,网上搜索了各种JS解决办法,包括 ...

  7. Java泛型中的? super T语法

    ? super T 语法将泛型类限制为所有T的超类(包括T自身),但只能用于参数中,不可以在返回值用加以限定.如果不加以限定,假设某个函数头为? super Manager get()由于编译器不知道 ...

  8. SQL获取汉字首字母

    )) ) as begin ) ) collate Chinese_PRC_CI_AS,letter )) insert into @t(chr,letter) select '吖','A' unio ...

  9. 转:js中this、call、apply的用法

    (一)关于this首先关于this我想说一句话,这句话记住了this的用法你也就差不多都能明白了:this指的是当前函数的对象.这句话可能比较绕,我会举出很多例子和这句话呼应的!(看下文)1.首先看下 ...

  10. [转]PYTHON-SCRAPY-WINDOWS下的安装笔记

    分类: Crawler.Net Python2014-05-15 13:36 127人阅读 评论(0) 收藏 举报 PYTHON SCRAPY 1.安装PYTHON2.7.6,下载地址:https:/ ...