Làm thế nào để thêm tin nhắn sẽ được đọc với dmesg?


44

Tôi đang cố gắng viết một số thông điệp tùy chỉnh trong đầu ra dmesg của tôi. Tôi đã thử:

logger "Hello"

dường như không hiệu quả. Nó thoát mà không có lỗi, nhưng không có "Hello" xuất hiện trong đầu ra của:

dmesg

Tôi đang sử dụng Fedora 9 và dường như không có syslogd / klogd daemon nào đang chạy. Tuy nhiên, tất cả các thông điệp kernel của tôi đều được viết trong bộ đệm dmesg.

Ý tưởng nào không?

Câu trả lời:


37

dmesghiển thị những gì trong bộ đệm kernel, trong khi đó loggerlà cho syslogd. Tôi nghĩ rằng nếu bạn muốn in mọi thứ vào bộ đệm kernel, bạn sẽ cần tạo một trình điều khiển sử dụng printk()chức năng kernel. Nếu bạn chỉ muốn nó vào /var/log/messages, thì với một thiết lập "bình thường" tôi nghĩ những gì bạn đã làm với loggerđã ổn rồi.

Ví dụ cơ bản nhất về trình điều khiển printk()sẽ là:

chào c:

#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");

}

Makefile:

obj-m += hello.o

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

Sau đó:

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

http://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN121 để biết thêm ...


Tôi đã gặp lỗi, vì bạn đã đặt dấu cách trước make -C ...Makefile thay vì Tab, do đó, sao chép nội dung trên của Makefile không hoạt động - thêm ở đây . Tôi dường như không thể thêm điều này trong một chỉnh sửa ... Cảm ơn, nhân tiện, câu trả lời tuyệt vời.
Wilf

107

Bạn có thể, như root, ghi vào /dev/kmsgđể in vào bộ đệm thông điệp kernel:

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

Tôi đã thử nghiệm điều này trên máy chủ của tôi và một thiết bị Linux nhúng và nó hoạt động trên cả hai, vì vậy tôi sẽ giả sử nó hoạt động khá nhiều ở mọi nơi.


1
Điều thú vị là trong Ubuntu, nó hoạt động như root nhưng không phải với sudo. Một người thực sự cần phải trở thành root.
dotancohen

15
Trên thực tế, đó là vì chuyển hướng đầu vào được xử lý bởi trình bao của bạn, vốn không chạy với quyền nâng cao. Hãy thử chạy echo Some message | sudo tee /dev/kmesgnhư không root.
wvdschel

3
Điều đó làm việc. Cảm ơn, thú vị. Nhân tiện, nó kmsgkhông kmesgnhưng tôi cũng nhầm lẫn với dmesgcái nào có e!
dotancohen

4
Dễ dàng hơn nhiều so với biên dịch mô-đun hạt nhân
e271p314

13

Dựa trên mô-đun của Kyle ở trên:


#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");

Để thực hiện in từ không gian người dùng:

echo "Hello" > /proc/printk

1
Cái này chỉ hoạt động với kernel Linux <3.10. Xem câu trả lời của tôi cho một sự thay thế mới hơn.
kevinf

5

Câu trả lời của @ Calandoa không còn hoạt động cho Kernel +3.10. Kết hợp mã của anh ấy và mã ví dụ tôi tìm thấy ở đây . Sau đó được cải thiện về chất lượng mã ...

Mã được lưu vào 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);

Sử dụng Makefile này

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

Dựa trên câu trả lời của Kyle, đây là một hướng dẫn nhanh chỉ ra cách làm điều đó.


2

Hình tôi sẽ tiếp tục và đưa vào một ví dụ đầy đủ về một thứ mà mọi người có thể biên dịch và chạy cho những người không thành thạo với C dựa trên câu trả lời của @BuvinJ

#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);
};

Để chạy, hãy lưu ở trên dưới dạng kmsg.c và gcc kmsg.c -o kmsg; sudo ./kmsg "chuỗi bạn muốn thêm vào / dev / kmsg"


0

Tôi chỉ muốn một số thông báo gỡ lỗi nhanh trong một daemon được viết bởi một người khác trong một hạt nhân tuân thủ chéo. Tôi gặp phải một lỗi biên dịch khi cố gắng sử dụng printk, vì <linux/module.h>không thể đưa vào. Thay vào đó, chiến đấu với điều đó quá mức (để làm điều này đúng cách) Tôi đã lừa dối và sử dụng cách giải quyết 5 phút lười biếng nhưng đầy chức năng sau đây:

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 ); }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.