如何添加将被dmesg读取的消息?


44

我正在尝试在dmesg输出中编写一些自定义消息。我试过了:

logger "Hello"

但这不起作用。它没有错误退出,但是在以下输出中没有出现“ Hello”:

dmesg

我正在使用Fedora 9,似乎没有syslogd / klogd守护程序在运行。但是,我所有的内核消息都已成功写入dmesg缓冲区中。

任何想法?

Answers:


37

dmesg显示内核缓冲区中的内容,而logger显示syslogd。我认为,如果要将内容打印到内核缓冲区中,则需要创建一个使用printk()内核功能的驱动程序。如果您只想在中/var/log/messages使用它,那么使用“常规”设置,我认为您已经做的logger很好。

驱动程序的最基本示例printk()是:

你好ç:

#include <linux/module.h>
#include <linux/kernel.h>

int init_module(void)
{
    printk(KERN_INFO "Hello world\n");
    return 0;
}

void cleanup_module(void)
{
    printk(KERN_INFO "Goodbye world\n");

}

生成文件:

obj-m += hello.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

然后:

$ make
$ sudo insmod hello.ko
$ dmesg | tail -n1
 [7089996.746366] Hello world

http://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN121了解更多...


我收到一个错误消息,因为您make -C ...在Makefile中而不是在Tab 之前放置了空格,因此复制Makefile的上述内容不起作用- 此处更多。我似乎无法在编辑中添加此内容...顺便说一句,谢谢。
2014年

107

您可以以root用户身份写入/dev/kmsg以打印到内核消息缓冲区:

 fixnum:~# echo Some message > /dev/kmsg
 fixnum:~# dmesg | tail -n1
 [28078118.692242] Some message

我已经在服务器和嵌入式Linux设备上对其进行了测试,并且可以在两者上使用,因此我假设它在任何地方都可以使用。


1
有趣的是,在Ubuntu中,它可以作为root用户使用,但不能与sudo一起使用。一个人实际上需要扎根。
dotancohen 2012年

15
实际上,这是因为输入重定向是由您的Shell处理的,它没有以提升的权限运行。尝试echo Some message | sudo tee /dev/kmesg以非root用户身份运行。
wvdschel

3
这样可行。谢谢,有趣。顺便说一句,它kmsg不是,kmesg但我也混淆了dmesg其中的e!
dotancohen 2012年

4
比编译内核模块容易得多
e271p314 2014年

13

基于上述Kyle的模块:


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>

static int pk_write(struct file *file, const char *buffer, unsigned long count, void *data)
{
        char string[256];
        count = count < 255 ? count : 255;

        if(copy_from_user(string, buffer, count))
                return -EFAULT;

        string[count] = '\0';        
        printk(string);
        return count;
}


static int __init printk_init(void)
{
        struct proc_dir_entry *pk_file;

        pk_file = create_proc_entry("printk", 0222, NULL);
        if(pk_file == NULL)
                return -ENOMEM;

        pk_file->write_proc = pk_write;
        pk_file->owner = THIS_MODULE;

        return 0;
}

static void __exit printk_cleanup(void)
{
        remove_proc_entry("printk", NULL);
}

module_init(printk_init);
module_exit(printk_cleanup);
MODULE_LICENSE("GPL");

要从用户空间执行printk:

echo "Hello" > /proc/printk

1
这仅适用于Linux内核<3.10。请参阅我的答案以获取更新的替代方法。
凯文夫2015年

5

@Calandoa的答案不再适用于内核+3.10。结合了他的代码和我在这里找到的示例代码。然后改进了代码质量...

代码已保存到printk_user.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>

static ssize_t write_proc(struct file *filep, const char *buffer, size_t count, loff_t *offsetp)
{
    char string[256];
    count = count < 255 ? count : 255;

    if(copy_from_user(string, buffer, count) != 0) {
        return -EFAULT;
    }

    string[count] = '\0';
    printk(string);
    return count;
}

static const struct file_operations proc_fops = {
    .owner = THIS_MODULE,
    .write = write_proc,
};

static int proc_init(void) {
    struct proc_dir_entry *proc_file;
    proc_file = proc_create("printk_user", 0, NULL, &proc_fops);

    if(proc_file == NULL) {
        return -ENOMEM;
    }

    return 0;
}

static void proc_cleanup(void) {
    remove_proc_entry("printk_user", NULL);
}

MODULE_LICENSE("GPL"); 
module_init(proc_init);
module_exit(proc_cleanup);

使用此Makefile进行制作

TARGET = printk_user
obj-m := $(TARGET).o

KERNEL_VERSION=$(shell uname -r)
KDIR = /lib/modules/$(KERNEL_VERSION)/build
PWD = $(shell pwd)

printk:
    $(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
    $(MAKE) -C $(KDIR) M=$(PWD) clean

3

根据Kyle的回答,是一个快速教程,显示了如何做到这一点。


2

想通了,我会继续介绍一个完整的例子,说明人们可以基于@BuvinJ的答案,对那些不熟悉C的人进行编译和运行

#include <stdio.h>
#include <string.h>
#include <fcntl.h> // open function
#include <unistd.h> // close function
#include "sys/syscall.h"


int main(); // Let's not worry about this for now

void dmesg( const char *tag, const char *msg, const int len )
{
    const int TAG_LEN=3;
    char buffer[128]={0};
    memcpy( &buffer[0], tag, TAG_LEN );
    memcpy( &buffer[TAG_LEN], msg, len );
    int fd_kmsg = open( "/dev/kmsg", O_WRONLY );
    write( fd_kmsg, &buffer, TAG_LEN+len );
    close( fd_kmsg );
}
void dmesgWarn(  const char *msg, const int len ){ dmesg( "<4>", msg, len ); }
void dmesgInfo(  const char *msg, const int len ){ dmesg( "<6>", msg, len ); }
void dmesgDebug( const char *msg, const int len ){ dmesg( "<7>", msg, len ); }


int main(int argc, char **argv)
{
    int getmysize = strlen(argv[1]);
    printf("%d\n", getmysize);

    printf("To be written: %s\nSize of argument: %d\n", argv[1], getmysize);
    // dmesgWarn dmesgInfo or dmesgDebug
    dmesgDebug(argv[1], getmysize);
};

运行时,将以上内容另存为kmsg.c和gcc kmsg.c -o kmsg; sudo ./kmsg“您要添加到/ dev / kmsg的字符串”


0

我只是想在交叉编译的内核中由其他人编写的守护程序中快速调试一些消息。我遇到了尝试使用的编译错误printk,因为<linux/module.h>无法包含在内。我宁愿与之争战(以正确的方式这样做),也作弊,并使用以下懒惰但实用的5分钟解决方法:

void dmesg( const char *tag, const char *msg, const int len )
{
    const int TAG_LEN=3;
    char buffer[128]={0};
    memcpy( &buffer[0], tag, TAG_LEN );
    memcpy( &buffer[TAG_LEN], msg, len );
    int fd_kmsg = open( "/dev/kmsg", O_WRONLY );
    write( fd_kmsg, &buffer, TAG_LEN+len );
    close( fd_kmsg );
}
void dmesgWarn(  const char *msg, const int len ){ dmesg( "<4>", msg, len ); }
void dmesgInfo(  const char *msg, const int len ){ dmesg( "<6>", msg, len ); }
void dmesgDebug( const char *msg, const int len ){ dmesg( "<7>", msg, len ); }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.